
[{"content":" Jump to... Hair Tools - Adjust Length Hair Tools - Attach Hair Tools - Collision Hair Tools - Deform Hair Tools - Deform Procedural Hair Tools - Extract Clumps Hair Tools - Prepare Hair Tools - Regrowth Hair Tools - Select Provided with the hair tools HDAs is an example scene that demonstrates the capabilities of each node and some example workflows.\nExample Name Description clump_twisting Demonstrate the effect of twist on deformed guides on a static mesh. clumps_on_curving_surface Guide tighteni keeps clumps together through significant mesh bending. ground_smoosh Character walks through grass with a custom smoosh solver, using hair_collision in a sop solver. hair_adjust_length Adjust the length of a curve, with polynomial extrapolation. hair_attach Demonstrates the advantages of hair_attach over guide_deform. hair_collision Demonstrates the use of the hair_collision node to handle post simulation curve penetrations. hair_deform Guided deformation of hair curves on a walking character. hair_extract_clumps Use hair_extract_clumps to identify clump and select representative guides. hair_regrowth Grow denser hair on a region of a mesh that already has hair. hair_select Examples for using hair_select to choose subsets of curves to use as guides. husk_procedural Workflow for using the hair_deform_procedural node to deform hair at render time. predeform_hair Workflow for pre-deforming hair to counteract the effect of gravity settling on a groom during simulation. whip_motion Fast moving ball of hair demonstrates clumps sticking together cleanly. ","externalUrl":null,"permalink":"/hair_tools/documentation/hair_examples/","section":"Hair Tools","summary":"","title":"Hair Tools - Example Scene","type":"hair_tools"},{"content":" force_table_of_contents # Jump to... Hair Tools - Adjust Length Hair Tools - Attach Hair Tools - Collision Hair Tools - Deform Hair Tools - Deform Procedural Hair Tools - Extract Clumps Hair Tools - Prepare Hair Tools - Regrowth Hair Tools - Example Scene Select a fraction of a dense groom to use as simulation or deformation guides.\nSelected hairs will be roughly evenly distributed across the skin.\nSee also: hair_extract_clumps to identify clumps and select a single representative guide.\nForced Selection # An optional third input may be provided to forcibly include curves near the roots of these provided curves. This can be used to add growth/clump guides along side an additional selection of dense curves to use as simulation guides.\nAlternatively, a specific selection of the dense curves may be selected and set as an input to get very specific guide selection for certain areas, but then rely on the random choice of this node to provide selection for other areas.\nSelection Weights # By default, guide selection is only based on getting an even distribution of points, choosing the closest root to a selection of evenly distributed surface points.\nA more advanced mode may be chosen where other criteria is considered as well, such as:* Root Distribution: Select guides with an even distribution across the surface.* Guide Length: The longest guide will be selected. This is important for situations where the most proximate curve is very short and we want to try to select a longer guide instead.* Guide Straightness: Straighter guides can often provide better results than ones that have a lot of bends.* Surface Normal Alignment: Guides that stick straight off the skin can sometimes be preferable to ones that are flat to the skin.\nDensity Mode # By default, selected guides have a uniform density, but this may be overridden by a density mask point attribute on the mesh.Additionally, a mask can be calculated based on mesh curvature.\nIf a curvature mask is used, the specific values to get a good selection will need to be dialed in.\nCurve Collision Radius # Each guide roughly represents a clump of the dense groom and are often used in simulations. Since we are evenly distributing the selection, we can determine curve width based on the proximity to its neighbors.\nNote that since the curve radius is determined by the proximity to its neighbors isolated guides may have a very large radius.\nShrink Large Outliers will force the curve radius to be the average if it is larger than the third standard deviation away from the average.\n","externalUrl":null,"permalink":"/hair_tools/documentation/hair_select/","section":"Hair Tools","summary":"","title":"Hair Tools - Select","type":"hair_tools"},{"content":" force_table_of_contents # Jump to... Hair Tools - Adjust Length Hair Tools - Attach Hair Tools - Collision Hair Tools - Deform Hair Tools - Deform Procedural Hair Tools - Extract Clumps Hair Tools - Prepare Hair Tools - Select Hair Tools - Example Scene Wraps hairgen with hair_prepare and the surface isolation techniques in hair_select for targetted curve generation based on guides.\nThis facilitates generating higher resolution hair for extreme closeups if the standard asset curves are too low resolution.\nThe controls are largely a subset of those found on hairgen.\nMesh Minimization # The primary use for this node is detecting where guided curves should be grown based on the area covered by the input curves.\n","externalUrl":null,"permalink":"/hair_tools/documentation/hair_regrowth/","section":"Hair Tools","summary":"","title":"Hair Tools - Regrowth","type":"hair_tools"},{"content":" force_table_of_contents # Jump to... Hair Tools - Adjust Length Hair Tools - Attach Hair Tools - Collision Hair Tools - Deform Hair Tools - Deform Procedural Hair Tools - Extract Clumps Hair Tools - Regrowth Hair Tools - Select Hair Tools - Example Scene Prepares curves to be used with a hair simulation and guide deformation system. These curves\u0026rsquo; start should be near the skin mesh. Any attributes that are missing will be created.\nSegment Length # Curve segment length is very important for detail, but too much detail can makesimulations unstable and extremely heavy and slow. Use the Segment Length parameter to override the segment length for the deformation groom.\nCurve Adjustments # Sometimes groom curves don\u0026rsquo;t match up with the mesh perfectly. This node can make adjustments to the curves to reattach them to the surface. However, keep in mind that this can make subtle adjustments to the silhouette of a character, so take care when applying curve adjustments. By default, no curve adjustment will occur.\nNote Optionally, roots may be adjusted to attach to the Open Subdivision limit surface for more accurate root placement.\nThis should be disabled if you are expecting the subivision limit surface offset to be calculated and applied separately, such as through the Yeti procedural.\nCurve Adjustment Options # None: No adjustments will occur. Move Root to Surface: Move the root point to the surface, leaving the rest of the hair as it was. Offset Whole Curve: Apply the root offset to the entire curve. Blend Whole Curve Offset: Apply the whole curve offset at the root, blending to the original curve at the tip.\nKeep Curve Length # After making adjustments to the curve, the curve length may not be the same as how it was originally groomed. This is typically a problem when we adjust the root without the tip or we apply skin collisions.\nTypically, we want to trim/extend curves sothat the curves are the same length as how it was groomed.\nRebuild Curves # After curves are adjusted or trimmed, the segment length may not be even between each point, which can result in unfortunate simulation artifacts.\nAfter the curve is rebuilt, the original attributes will be interpolated from the source curves onto the new ones.\nMesh Collision # Sometimes curves will be authored in such a way that they penetrate the mesh. This is especially problematic for curves authored by third parties or when we want to use a mesh variation with the same groom.\nAttributes # Disable Root Collisions # The roots will be lying directly on the skin surface and can cause some energy to enter the system if a collision is detected with the skin upon which it lies. Enable this option to disable root point collisions with colliders.\nSkin Attributes # Any attribute here will be transferred from point, vertex, or prim to the output curves.\nThis defaults to uv, so shaders can pick up surfacing colors of the skin, for situations like a cow\u0026rsquo;s black and white patches.\nIf N is included, but N is not explicitly present on the incoming mesh, it will be calcuated.\n","externalUrl":null,"permalink":"/hair_tools/documentation/hair_prepare/","section":"Hair Tools","summary":"","title":"Hair Tools - Prepare","type":"hair_tools"},{"content":" force_table_of_contents # Jump to... Hair Tools - Adjust Length Hair Tools - Attach Hair Tools - Collision Hair Tools - Deform Hair Tools - Deform Procedural Hair Tools - Prepare Hair Tools - Regrowth Hair Tools - Select Hair Tools - Example Scene Selects or generates guide curves from a dense groom by first clustering curves that follow similar trajectories, then either picking the most representative curve per clump or generating a synthetic centroid guide. Clustering is based on trajectory proximity rather than just root distance, so curves that travel together are grouped even if their roots are spread apart.\nAn alternative entry point allows externally provided clump IDs to be used instead of the automatic clustering.\nBy default, the input groom is shown as a guide, with color coding shown to identify the clumps.\nSee also: hair_select to select a subset of representative guides with an even mesh distribution.\nClustering # Curves are clustered using trajectory proximity. For each curve, the K nearest root neighbors are found, then trajectory samples at regular arc fractions are compared. If the mean nearest-sample distance between two curves is small relative to their length, they are merged into the same clump via union-find.\nThe sample start parameter skips the root region of the curve, avoiding false groupings of curves that share a common base but diverge further along. Clumps smaller than the minimum size are dissolved and their curves reassigned to the nearest larger clump.\nExternal Clump IDs # When clump assignments are provided externally as a clump ID attribute on prims, automatic clustering can be bypassed. The system reads the existing IDs and computes the clump count for downstream processing.\nGuide Selection # Selects the most representative existing curve per clump. A centroid trajectory is computed at regular arc slices, then each curve is scored by its distance to the centroid. The score is weighted by straightness and length penalties — higher bias values more strongly prefer straighter and longer curves.\nCurves shorter than the minimum length ratio (relative to the longest curve in the clump) are excluded from selection. Curves that end before a given arc slice use the tip-to-centroid distance for the remaining slices, naturally penalizing short curves.\nThe selected curve is tagged with the guide prim group, and all curves in the clump receive the guide\u0026rsquo;s primitive number as their guideid.\nGuide Generation # As an alternative to guide selection, synthetic guide curves can be generated through each clump\u0026rsquo;s centroid. The clump is sliced with planes perpendicular to its overall direction, and all curve points whose projection falls in a given bin contribute to the centroid position at that slice.\nPoint attributes (width, pscale, Cd, etc.) are averaged per bin. Prim attributes are averaged across clump members. Laplacian smoothing is applied to the generated guide to remove noise.\nClump Width # After guide selection or generation, the clump width is measured at each guide point. A perpendicular slab is defined using the local guide tangent, all clump curve points within the slab are collected, and the average distance to the guide point is computed.\nThe slab fraction controls the thickness of the measurement region as a fraction of the guide\u0026rsquo;s arc length. Smaller values give more local measurements; larger values average over more of the clump.\nThe resulting per-point clump width can be used downstream for clump shaping, width-based effects, or visualization.\nClump Radius # It can sometimes be useful to determine the width of a clump, so this optional output will try to determine the width of the clump for use with simulation or collisions.\n","externalUrl":null,"permalink":"/hair_tools/documentation/hair_extract_clumps/","section":"Hair Tools","summary":"","title":"Hair Tools - Extract Clumps","type":"hair_tools"},{"content":" force_table_of_contents # Jump to... Hair Tools - Adjust Length Hair Tools - Attach Hair Tools - Collision Hair Tools - Deform Hair Tools - Extract Clumps Hair Tools - Prepare Hair Tools - Regrowth Hair Tools - Select Hair Tools - Example Scene This node captures nearby sparse guides and deforms a set of dense curves.\nSee hair_deform for more information.\nNote The result will update the input Deformed Curves at render time, so material bindings will stay attached.\nNote The Guide prims will be set to guide purpose.\nWarning Guide and Skin prims must have a primvars:rest primvar.\nWarning Due to the way husk procedurals are invoked, none of the inputs may be proxy purpose.\nDifferences from the SOP # This node is not exactly like the SOP equivalent in the following ways:\nUncaptured curves will simply be removed. The SOP node takes five inputs, but this only requires three, with the guides and the mesh requiring a primvars:rest primvar in order to function. The result of the procedural cannot be seen until rendered through husk or previewed with houdinipreviewprocedurals. Deformation cannot be disabled via a parameter. If you want to disable it, bypass or remove the node. Output attributes, like captured guides and weights, are not exported. Debug mode is not available. It can be useful to set up a Sop hair_deform with channel references to trouble-shoot, since they use the same capture and deformation logic. Workflow # The general workflow for working with this procedural will largely match the SOP, with some potential differences:\nIt is crucial that both the mesh and guides have a primvars:rest primvar. It may be useful to use a hair_deform in capture-only mode to capture guides in an environment where debugging is easier to do. ","externalUrl":null,"permalink":"/hair_tools/documentation/hair_deform_procedural/","section":"Hair Tools","summary":"","title":"Hair Tools - Deform Procedural","type":"hair_tools"},{"content":" force_table_of_contents # Jump to... Hair Tools - Adjust Length Hair Tools - Attach Hair Tools - Collision Hair Tools - Deform Procedural Hair Tools - Extract Clumps Hair Tools - Prepare Hair Tools - Regrowth Hair Tools - Select Hair Tools - Example Scene This node captures nearby sparse guides and deforms a set of dense curves based on the way those guides have been modified. Nearby guides are selected based on criteria such as hair-guide alignment and similar lengths, up to a limit.\nOutputs # This node produces two outputs:\nDeformed curves. Curves that could not find any capture weights, and thus could not be deformed. You can then either leave them out from the output to delete them or deform them in some other manner. These curves can be optionally included in the output as a skin deformation, which is suitable for short hair. Workflow # The general workflow for working with this curve deformation system is:\nLoad a dense groom. This may or may not come from Houdini. Use the hair_prepare node to transfer necessary skin attachment attributes to each primitive. Use hair_select or hair_extract_clumps to select simulation guides from the set of dense curves, or import existing guides and use hair_prepare to similarly prepare the guides for mesh attachment. Simulate or otherwise deform the guides (a procedural application of hair_collision may be sufficient). Use this node (hair_deform) to associate guides with each curve of the dense set and deform them to the animated guides. Use hair_collision to push any guided curves out of the collision shapes in a post sim operation, if necessary. Profit. Capture # Finds nearby guides to build a weighted deformation spline. The resulting deformation spline will be a weighted composite of the animation on the captured guides.\nCapture Criteria # Many guides are considered as a deformer and the nearest few that meet the following criteria will be used:\nSearch Radius Scale: A scale on the guide search radius. Can help dial in the right capture weighting for calculated guide search radius. Minimum Guide Alignment: An alignment vector is established by building vectors between the root and tip of the two curves, then comparing the angle between them. The angle must be lower than the provided number of radians to be considered as a guide. This is the maximum number of radians allowed between a guide and a curve. A value of 0 requires the curve and guide to be perfectly aligned. A value of $PI/2 will allow a 180 degree angle (90 degrees on either side) between the guide and curve. Minimum Length Ratio: Guides must be at least as long as this ratio to be considered. We do not want very short guides to drive the deformation of a long curve, since the tip of a curve could be inappropriately deformed by a small guides. The ratio is calculated by multiplying the curve length by this ratio, then comparing the prospetive guide to that value. Maximum Length Ratio: (Optional) Guides must not be longer than this ratio to be considered. This is optional, since typically a longer guide can still adequately deform a shorter curve. However, since long guides may interact with different colliders, we may want to select only guides that are closer to the curve length. Capture Radius # The guide capture radius may be explicitly set or it may be calculated.If the capture radius is calculated, it will be determined based on the distance between nearby guides. This means that tighter guide distribution will have a smaller search radius. This may be beneficial so that localized densities may be used to determine guide weighting.\nCapture Iterations # We begin with the most aggressive capture criteria, but that will often result in many curves uncaptured.\nWe iteratively capture guides with more and more permissive critera to give ourselves the best possible chance of finding good guides, while still reducing the chances of leaving uncaptured guides.\nExisting Capture Attributes # You can ignore the capture process entirely, if each curve primitive has a guides int array and a weights.\nNote The guides array contains the primitive numbers of the guides on the guide geometry. This means that the guide geometry topology must remain consistent to when the array was initially created. Since this is based on primitive numbers (not id), you cannot build a guides array and then use hair_select, without fixing the guide selection values after selection.\nDeformation # Given a weighted deformation spline, use the curve\u0026rsquo;s parametric u value to determine an appropriate offset.\nGuide Extrapolation # Captured guides that are shorter than the curve will be extrapolated to the full curve length, which allows for a smooth and natural feel even with less-than-ideal guides.\nGuides can be extapolated linearly or polynomially, which will continue the curvature at the tip.\nDisplacement # Displacement Modes # The displacement mode combo offers three choices: Translate, Swing (Slide), and Swing (Pinned). All read the same blended per-curve guide; they differ in how a strand follows it.\nTranslate # Each strand keeps its rest shape and is simply moved to follow its guide. However far the guide has shifted from its rest pose to the animated pose, every point on the attached strands is pushed by that same amount, like picking up the hair and setting it down wherever the guide went.\nBecause the strands only slide with the guide, they do not reorient when the guide bends or twists; they hold their rest orientation, and the clump is kept from stretching or collapsing by the distance constraints. This looks great when the guide motion is mostly drift or sway, and less convincing when the guide bends or curls sharply, since the strands will not rotate to follow that bend.\nSwing # Each strand rides on the guide as if pinned to a frame that bends and spins along with it. As the guide curves or twists from its rest pose into the animated pose, the strand swings and rotates to match, the way clumped hair naturally pivots around the strand it is following.\nInstead of just relocating the hair, this preserves the strand\u0026rsquo;s shape relative to the guide, so curling, bending, and twisting guides all read cleanly.\nSwing offers two ways to anchor each point along its guide:\nSlide: points slide freely along the guide so the strand holds its rest length through a bend. This is the right choice for straight or gently bending guides, where keeping exact length matters most. Pinned: each point is pinned to a fixed fraction of the guide and never slides, so the motion stays clean on tight curls. The strand\u0026rsquo;s length then follows the bend rather than being held exactly. Prefer this on curly guides, where a sliding point tends to read as noise crawling down the strand. Curve Processing # Curves may change length after the raw offsets are applied, so we also forcibly trim/extend the curves to their original length.\nGuide Tightening will attempt to keep a stable distance of the curves to the guides through deformation.\nTwist # If twist is enabled, curves will rotate around the guide at the number of radians, interpolated along its length.\nIf the guide is shorter than the curve, the twist can be extrapolated, held,or normalized to the full length of the extrapolated guide.\nGuide Tightening # After deformation, it is often the case that a clump shape will splay out, especially if the surface skin has bent relative to its neighbors.\nGuide Tightening will pull deformed curves back to its relative distance from the guide, if it is further away from its distance at rest.\nNote that this only applies to curves that end up further away from their distance at rest. If the curve is inside the target distance, it will be left as it is.\nVelocity # Transfers velocity and acceleration from the animated guides to the deformed curve points in a single pass. The pass runs unconditionally and requires v on the incoming guides; accel is an optional value-add that enables the acceleration output and a more accurate reconstruction (see Source Attributes).\nSource Attributes # Velocity is computed upstream on the animated guide points before they enter the guide deformer. Use a Trail SOP on the anim guide curves. Setting it to \u0026ldquo;Compute Velocity and Acceleration\u0026rdquo; is recommended: the added accel lets the transfer use that mode\u0026rsquo;s centered differencing to reconstruct the neighboring frames it reads the guide\u0026rsquo;s rotation from, and emits an acceleration output. With velocity only it falls back to a backward-difference reconstruction (off by about half a frame) and writes no accel.\nAttribute Type Required Description v vector yes Point velocity from guide animation accel vector no Point acceleration from guide animation twist_rate float no Twist angular velocity in radians per second The incoming guide v and accel should have \u0026ldquo;vector\u0026rdquo; type info (the Trail SOP sets this by default). The node tags its own output v and accel as \u0026ldquo;vector\u0026rdquo; automatically, so the downstream transformbyattrib rotates them from rest into anim space.\nv is required: if it is absent the velocity pass is skipped entirely. accel and twist_rate are optional value-adds, disabled automatically when missing — without accel the pass uses a velocity-only reconstruction and writes no acceleration; without twist_rate the twist-rate contribution is dropped.\nMethod # In a single pass, each point is transported rigidly about its guide pivot. The angular velocity and angular acceleration are measured from how the guide tangent rotates between reconstructed neighboring frames, so the velocity swing follows the same geometry as the position deform.\nBecause it transports rigidly about the guide, it does not capture the small tangential sliding introduced by the resample redistribution or the target-space constraint; for hair those residuals lie mostly along the strand, the least visible direction for motion blur.\nComputing Twist Rate # No built-in Houdini node computes twist rate. Use a wrangle with a Time Shift on the second input:\nInput 0: current frame anim guides (with twist) Input 1: previous frame anim guides (Time Shift, frame - 1) float tw_cur = f@twist; float tw_prev = float(point(1, \u0026#34;twist\u0026#34;, @ptnum)); f@twist_rate = (tw_cur - tw_prev) * @TimeInc; Troubleshooting # Debug Mode # Curve deformation can often be difficult to diagnose.\nSetting Debug to Guide Selection allows users to select specific curve ids.\nSelected curves will show their captured guides in a dimmer color, both in their rest (blue) and deformed (red) psotiions.\nUsing the selection button allows selection by curve id.\nAlternatively, setting Debug to Extrapolated Guides shows the extrapolated guides that will be used as the guide used for a given curve.\nThe main issues to consider when troubleshooting are:\nDeformed curves are penetrating collision surfaces: Use hair_collision to bump the hair back into position. Curves are being deformed by inappropriate guides: Consider making the capture criteria more stringent, and increase the number of iterations. Alternatively, select more guides. Oftentimes, more guides are necessary around collision surfaces, such as a shirt collar. Guides are clearly identfiable in the clumping: Increase the maximum number of used guides. Deformation is too mushy: Decrease the maximum number of used guides, to get more discrete deformation. ","externalUrl":null,"permalink":"/hair_tools/documentation/hair_deform/","section":"Hair Tools","summary":"","title":"Hair Tools - Deform","type":"hair_tools"},{"content":" force_table_of_contents # Jump to... Hair Tools - Adjust Length Hair Tools - Attach Hair Tools - Deform Hair Tools - Deform Procedural Hair Tools - Extract Clumps Hair Tools - Prepare Hair Tools - Regrowth Hair Tools - Select Hair Tools - Example Scene Deflects curves away from collider surfaces, applies friction near the surface, and restores the original curve length afterward. Collision is evaluated against an SDF volume — curves are reconstructed point-by-point from root to tip, reflecting off the surface when they penetrate.\nNote This is a procedural collision resolver, so it makes no claim for temporal stability. For temporal stability, collisions must be resolved during a simulation, either directly during the primary simulation, or with this node in a sop solver. See the ground smoosh example for more details.\nCurves # Curves may be sampled at a higher rate than they come in for better collision resolution. The higher resolution collision positions will then be interpolated back on to the original curves to preserve topological consistency.\nCollisions # Curves are resolved in such a way that curves will reflect off collision surfaces and will not result in instabilities around the length, unlike a standard point collision method.\nBoth polygons and SDFs are supported as collisions. If polygons are provided, they will be converted to an SDF.\nSoft Collisions # Soft collision depth controls how sharply the collision activates. At 0, collision is binary (in or out). Higher values produce a gradual blend into the reflected direction over the specified depth, softening the transition.\nSometimes it is preferable for a curve to be allowed to slightly penetrate a collision body. Enabling Soft Collision will blend in the collision behavior over a certain depth into the SDF.\nBy default, this is set to be the amount of Surface Offset so that the original collision surface is still considered \u0026lsquo;hard\u0026rsquo;.\nThis can be a useful tool for reducing high frequency jitting over time when colliding with high resolution SDFs.\nCollision Correction # Collision correction optionally pushes colliding points outward along the surface normal, helping curves clear the surface rather than sliding exactly along it.\nDeflection # After a collision, the accumulated deflection orientation is tracked and blended into subsequent points. This causes the curve to continue bending away from the surface rather than immediately returning to its rest direction.\nStiffness # By default, hair_collision will bend directly at the collision site. This can look awkward for dry hair, so the stiffness parameter can be turned up to blend the collision into the rest of the curve to have a more natural feel.\nFriction # Points near the collider surface have their position and velocity blended toward the collider\u0026rsquo;s velocity field. This simulates surface friction — curves close to the skin move with it.\nFriction activates within a configurable distance from the surface, with an optional soft falloff zone for gradual blending. Position update can be disabled to affect only velocity.\nWhen friction is applied, the surface velocity will be copied to the curves within a capture distance.\nOptionally, the friction can be applied to position directly.\nNote the velocity will be sampled from the vel field of an existing SDF, and if polygons are provided, v is expected to be set.\nTroubleshooting # The main issues to consider when troubleshooting are:\nCurves being \u0026rsquo;trapped\u0026rsquo; just inside the collision surface: Consider enablng Collision Correction or Deflection. Collisions are too high frequency and jittery over time: Consider enabling Soft Collision or increasing the Voxel Size to get a lower resolution collider. Points on curves are all smashing together or are creating high-frequency, jagged shapes after a collision: Consider enabling Overlap Relaxations. Curves are inside the collision shape: Ensure the SDF is high enough resolution to generate capture the gradient to the surface. Small, thin collision shapes require very high resolution SDFs. Also ensure that the curves don\u0026rsquo;t start inside the collision shape. ","externalUrl":null,"permalink":"/hair_tools/documentation/hair_collision/","section":"Hair Tools","summary":"","title":"Hair Tools - Collision","type":"hair_tools"},{"content":" force_table_of_contents # Jump to... Hair Tools - Adjust Length Hair Tools - Collision Hair Tools - Deform Hair Tools - Deform Procedural Hair Tools - Extract Clumps Hair Tools - Prepare Hair Tools - Regrowth Hair Tools - Select Hair Tools - Example Scene Hair Attach computes a per-curve rigid transform that moves curves from their rest position to the animated skin position. It works by comparing a rest mesh to an animated mesh and interpolating the resulting rotation and translation at each curve\u0026rsquo;s skin attachment point.\nThe optional output is a 4x4 matrix stored as a primitive attribute that downstream nodes can use to deform curves.\nHow It Works # The rest mesh is initialized with axis-aligned basis vectors at each point. When the animated mesh deforms, the basis vectors rotate with it. By comparing the deformed basis to the rest basis, a per-point rotation, pivot, and translation are computed.\nEach curve\u0026rsquo;s root is bound to a mesh face via skinprim / skinprimuv. The deformation is interpolated at that UV position using either standard primuv or OSD limit surface evaluation, then assembled into a single rest-to-anim matrix per curve.\nThe OSD limit surface option produces smoother interpolation on subdivision surfaces by evaluating at the limit rather than on the control hull.\nWarning Collisions are not resolved during attachment. This node simply applies the local transform at the root to the curves and it is likely that a collision with the skin will occur.\n","externalUrl":null,"permalink":"/hair_tools/documentation/hair_attach/","section":"Hair Tools","summary":"","title":"Hair Tools - Attach","type":"hair_tools"},{"content":" force_table_of_contents # Jump to... Hair Tools - Attach Hair Tools - Collision Hair Tools - Deform Hair Tools - Deform Procedural Hair Tools - Extract Clumps Hair Tools - Prepare Hair Tools - Regrowth Hair Tools - Select Hair Tools - Example Scene Adjust Length changes the length of groom curves while preserving their shape. Curves that need to grow are extended from the tip; curves that need to shrink are trimmed. After length adjustment, curves can optionally be aligned toward the skin surface normal and/or straightened. A final resample pass can change the point count to meet segment distance or count requirements.\nAll controls can be driven per-curve from parameters, curve attributes, or mesh attributes painted on the skin surface.\nAdjustments # Length # The target length for each curve is computed as:\ntarget = clamp(base_length * scale + offset, minimum, maximum)\nWhere base_length is the curve\u0026rsquo;s current arc length.\nEach component can be independently enabled or disabled:\nControl Default Description Set Length off Overrides the base length with an explicit value instead of using the curve\u0026rsquo;s measured arc length. Scale 1.0 Multiplier on the base length. Values less than 1 shorten, greater than 1 lengthen. Offset 0.0 Added after scale. Positive values lengthen, negative shorten. Minimum 0.0001 Floor clamp. Curves will never be shorter than this. Maximum off Ceiling clamp. When enabled, curves will never be longer than this. Tip Extrapolation # When a curve grows beyond its original length, new positions must be generated past the tip. Two extrapolation modes are available:\nLinear (default): Extends in a straight line along the tip tangent. Polynomial: Continues the tip\u0026rsquo;s curvature with exponential decay, producing a natural-looking arc that gradually straightens. The Decay parameter controls how quickly the curvature fades. Attribute Handling During Extension # When curves are extended, point attributes on the new positions need values. Three modes control this per attribute:\nInterpolate (default): The attribute is stretched to cover the full target length. The original value distribution is remapped proportionally across the new length. Extrapolate: The attribute is linearly extended from its last two values. Quaternion attributes extrapolate by repeating the tip\u0026rsquo;s delta rotation, preserving spin. List attributes in the Extrapolate Attributes field (space-separated). Hold: The original distribution is preserved at its original arc positions. Positions beyond the original tip hold the tip value. List attributes in the Hold Attributes field (space-separated). Shape # These controls modify the curve\u0026rsquo;s shape and surface alignment.\nControl Range Description Surface Alignment 0..1 Blends the root tangent toward the skin surface normal. At 1.0, the curve base points straight out from the surface. Straightness 0..1 Blends each point\u0026rsquo;s orientation toward a straight line. At 1.0, all curvature is removed. Smoothing 0..100+ Reduces the orientation delta between segments to minimize high frequency noise. With higher Smoothing Iterations, progressively lower frequency noise will be smoothed out. Combined at full strength, these produce a straight curve perpendicular to the skin — useful as a starting point for procedural styling.\nSmoothing Iterations controls how many relaxation passes the Smooth strength is applied over — more iterations spread the smoothing further along the curve. It defaults to the node parameter, but can be overridden per-curve from a parameter, curve attribute, or mesh attribute like the other controls.\nPin Tip anchors each curve\u0026rsquo;s tip to its original position while smoothing. By default smoothing keeps the root fixed and lets the tip drift as the interior relaxes; with Pin Tip enabled the tip\u0026rsquo;s drift is distributed back along the curve so both ends stay put. This slightly alters segment lengths (which are otherwise preserved exactly).\nAttribute Sources # Every control above supports three source modes:\nSource || Description || Parameter | Uses the value set directly on the node. All curves get the same value. Curve Attribute | Reads from a named attribute on each curve. When reference curves are connected (Input 2), reads from the reference instead. Checks prim attributes first, then falls back to the root point. Mesh Attribute | Samples a named attribute from the rest mesh at each curve\u0026rsquo;s root position (via skinprim/skinprimuv). Useful for painted maps that vary across the surface.\nSet Length from Reference Curves: When Set Length is enabled with source set to Reference Curve Length, the length is measured directly from the corresponding reference curve on Input 2 using its arc length. This requires that the reference curves on Input 2 have matching primitive numbers — each curve on Input 0 reads the length of the reference primitive with the same @primnum. If the reference primitive is missing or has zero length, the curve\u0026rsquo;s own length is used as a fallback.\nResampling # After length adjustment and alignment, an optional resample pass can change the number of points on each curve. This is useful for matching segment density requirements or reducing point counts.\nControl Default Description Segment Length off When enabled, computes the point count from a target distance between points. Shorter distances produce more points. Max Segments off When enabled, caps the segment count to a hard upper limit. Applied after segment length computation. Min Segments 3 Floor on segment count. Curves will always have at least this many segments regardless of other settings. The Minimum Segment Distance control (on the length adjustment) interacts with resampling: if the target length divided by the current segment count would produce segments shorter than this distance, it either reduces the segment count or grows the length to compensate (depending on mode). This minimum is also respected by the resample pass when computing point counts.\nIf the computed point count equals the original, the resample pass is skipped entirely.\nOptional Output Attributes # By default, Adjust Length only modifies curve positions. Output attributes can be individually enabled and written to configurable names on the original input curves.\nAttribute Type Description ptdist point float Averaged distance to neighboring points (half-segment on each side). segdist point float Distance from each point to the previous point (0 at root). tangentu point vector Unit tangent direction along the curve. curveu point float Arc-length parameterized 0..1 along the final curve. orient point vector4 Absolute orientation frame at each point. delta_orient point vector4 Relative frame rotation between consecutive points. rest_length prim float Final measured arc length of the processed curve. ","externalUrl":null,"permalink":"/hair_tools/documentation/hair_adjust_length/","section":"Hair Tools","summary":"","title":"Hair Tools - Adjust Length","type":"hair_tools"},{"content":"","externalUrl":null,"permalink":"/authors/","section":"Authors","summary":"","title":"Authors","type":"authors"},{"content":"I\u0026rsquo;ve spent over twenty years in visual effects and animation, first as an FX artist and then as a pipeline engineer. I\u0026rsquo;ve worked my way through Pixar, DreamWorks, and Iloura as a shot artist. Somewhere along the way found that I loved building the tools that help other artists do their best work even more than doing the work itself. These days I lead a pipeline development team, where I focus on Houdini tooling and USD-based workflows.\nPipeline # Coming from an artistic background, the friction points in a pipeline tend to be pretty familiar, and that shapes where my priorities land.\nMost of my pipeline work has been Houdini-centric: building departments around USD at Scanline, Luma Pictures, and Iloura, with a focus on keeping the underlying complexity out of the artist\u0026rsquo;s way. Alongside the pipeline work I\u0026rsquo;ve built a lot of HDAs over the years: tools for solving difficult shots, improving day-to-day workflows, and hitting creative targets that would otherwise be out of reach.\nThe parts of the job I find most rewarding tend to sit between the technical and the human side. I love hosting training seminars, mentoring TDs, writing documentation that people will actually read. I think good pipeline work is as much about communication as it is about code, and I try to write software the same way: clearly, with the next person in mind.\nAs an Artist # Before moving into pipeline full-time, I spent years as an FX artist at Pixar, DreamWorks Animation, and Iloura, working on a wide range of films and television. I\u0026rsquo;ve led FX teams on projects like Thor: Love and Thunder, Spider-Man: Far From Home, Game of Thrones: Battle of the Bastards, How to Train Your Dragon, and The Incredibles, among many others.\nThat experience shapes how I approach every pipeline problem. I know what a deadline feels like from the other side of the tools.\nFull credits available on IMDb.\nContact # Questions? Feedback? Pop me an email.\nFor questions regarding licenses, please contact sales.\n","externalUrl":null,"permalink":"/profile/","section":"Ben Andersen","summary":"","title":"Ben Andersen","type":"profile"},{"content":"","externalUrl":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":" Hair Tools # v1.17 21 June 2026 FX/Core Indie Apprentice Hair Tools require Houdini 21.0 or greater. License Server # v1.4 21 June 2026 Linux Windows MacOS (Silicon) MacOS (Intel) ","externalUrl":null,"permalink":"/download/","section":"Download","summary":"","title":"Download","type":"download"},{"content":" v1.17 21 June 2026 FX/Core Indie Apprentice Previous releases v1.16 3 June 2026 FX/Core Indie Apprentice v1.15 2 June 2026 FX/Core Indie Apprentice v1.14 27 May 2026 FX/Core Indie Apprentice v1.13 26 May 2026 FX/Core Indie Apprentice ","externalUrl":null,"permalink":"/hair_tools/download/","section":"Hair Tools","summary":"","title":"Download","type":"hair_tools"},{"content":" v1.4 21 June 2026 Linux Windows MacOS (Silicon) MacOS (Intel) Previous releases v1.3 2 June 2026 Linux Windows MacOS (Silicon) MacOS (Intel) v1.2 26 May 2026 Linux Windows MacOS (Silicon) MacOS (Intel) ","externalUrl":null,"permalink":"/license_server/download/","section":"License Server","summary":"","title":"Download","type":"license_server"},{"content":"A suite of tools for deforming and procedurally manipulating hair and fur grooms in Houdini. Rather than authoring a groom from scratch, these nodes take an existing groom and help you get it moving. They are designed to sit around your simulation pipeline, handling everything before and after the sim itself.\nThese tools grew out of my own CFX work. I built them to solve problems I kept running into on real productions, and refined them every time a new shot pushed them somewhere unexpected. Over time, the artists around me started reaching for them too, and eventually they became a quiet staple of the pipeline wherever I worked. It felt like the right moment to clean them up, document them properly, and make them available to everyone grinding through the same problems.\nDownload # v1.17 21 June 2026 FX/Core Indie Apprentice Hair Tools require Houdini 21.0 or greater. Documentation # These tools require a license. Hair Adjust Length Grows or trims curves to a target length without losing their shape, with full per-curve art direction via painted maps.\nHair Attach Sticks groom roots to an animated character skin. The fast, lightweight first step in any hair pipeline.\nHair Collision Pushes hair clear of character surfaces with built-in friction, stiffness, and soft-blending controls for natural results.\nHair Deform Drives a full dense groom from sparse simulation guides, with clump tightening, twist, and an interactive debug mode.\nHair Deform Procedural A render-time version of Hair Deform that deforms dense curves against guides in Husk, with no pre-cached groom required.\nHair Extract Clumps Automatically groups a dense groom into natural clumps and picks a representative guide for each one.\nHair Prepare Snaps roots, evens point spacing, resolves penetrations, and transfers skin attributes. The essential first step before simulation.\nHair Regrowth Generates a close-up-ready dense groom from existing guides without re-grooming from scratch.\nHair Select Picks an evenly distributed subset of curves to serve as simulation guides, with neighbor-based collision width ready to feed straight into a sim.\nExample Workflow Scene # Hair Examples A scene file with example workflows that demonstrate the capabilites of each node.\n","externalUrl":null,"permalink":"/hair_tools/","section":"Hair Tools","summary":"","title":"Hair Tools","type":"hair_tools"},{"content":" Jump to... Hair Tools - Adjust Length Hair Tools - Attach Hair Tools - Collision Hair Tools - Deform Hair Tools - Deform Procedural Hair Tools - Extract Clumps Hair Tools - Prepare Hair Tools - Regrowth Hair Tools - Select Hair Tools - Example Scene A suite of Houdini nodes for hair and fur pipelines, designed to integrate cleanly into a production environment without displacing the tools and workflows already in place. None of the nodes require the others to function. Each one does its job independently and works alongside whatever else an artist already has in their scene. You can adopt a single node for a specific problem, build a full pipeline around the suite, or anything in between.\nGetting started # If you\u0026rsquo;re new to the suite, a typical starting point is Hair Prepare, which conditions incoming curves and computes the attributes that downstream nodes expect. From there the workflow depends on what you\u0026rsquo;re working on. The documentation for each node covers how it connects to the others.\nSee the example scene for a demonstration of the tools themselves.\nDeformation Workflow # The general workflow for working with this curve deformation system is:\nLoad a dense groom. This may or may not come from Houdini. Use the hair_prepare node to transfer necessary skin attachment attributes to each primitive. Use hair_select or hair_extract_clumps to select simulation guides from the set of dense curves, or import existing guides and use hair_prepare to similarly prepare the guides for mesh attachment. Simulate or otherwise deform the guides (a procedural application of hair_collision may be sufficient). Use hair_deform to associate guides with each curve of the dense set and deform them to the animated guides. Use hair_collision to push any guided curves out of the collision shapes in a post sim operation, if necessary. Profit. ","externalUrl":null,"permalink":"/hair_tools/documentation/","section":"Hair Tools","summary":"","title":"Hair Tools Documentation","type":"hair_tools"},{"content":"","externalUrl":null,"permalink":"/","section":"Home","summary":"","title":"Home","type":"page"},{"content":"","externalUrl":null,"permalink":"/home/","section":"Homes","summary":"","title":"Homes","type":"home"},{"content":" Geometric — 2D\nhexagon circle square triangle diamond octagon star cross arrow grid wave spiral eye warning Platonic Solids — 3D\ntetrahedron cube octahedron dodecahedron icosahedron Hair Tools\nhair-adjust-length hair-attach hair-collision hair-deform hair-deform-procedural hair-extract-clumps hair-prepare hair-regrowth hair-select Products\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?\u003e logo hair-suite hair-example license-server Other\napple-intel apple-silicon download houdini-file iso-houdini tux windows ","externalUrl":null,"permalink":"/icons/","section":"Icons","summary":"","title":"Icons","type":"icons"},{"content":"The tools are protected by a floating license, which means a small license server needs to be running somewhere on your network.\nThis will typically be a workstation, a studio server, or any machine that stays on during the day.\nOnce it\u0026rsquo;s up, any machine on the same network can use the tools without any per-machine configuration.\nFor a single artist working at home, that usually just means running the server on the same machine you work on.\nDownload # v1.4 21 June 2026 Linux Windows MacOS (Silicon) MacOS (Intel) Setup Instructions Instructions for installation and setup of the license server software.\n","externalUrl":null,"permalink":"/license_server/","section":"License Server","summary":"","title":"License Server","type":"license_server"},{"content":"The Hair Tools HDAs all consume a license when they cook.\nLicenses are sold as yearly rentals and are floating, served from a locally installed license server. One license covers one concurrent user from anywhere on your network.\nHow It Works # Licenses are only checked out when the node cooks. This means that a scene that includes these nodes does not necessarily check out a license. It is safe for a lighter to open a CFX artist\u0026rsquo;s scene, as long as they don\u0026rsquo;t cook those nodes.\nLicenses are returned when Houdini closes. If Houdini has a hard crash, the license will be returned after a short time.\nInteractive sessions use a different license from batch/hython sessions, so you\u0026rsquo;ll need a batch license for each farm machine that might pick up a hair caching job.\nMultiple processes on the same machine will only consume one license.\nLicenses are floating, but are locked to the local License Server. The same license file cannot be used on two different networks.\nThe Hair Deform Procedural node will consume the procedural license type.\nEngine Usage Since the procedural generates curves, not polygons, it will not consume an engine license. Check out the --allowed-procedurals option on the husk page for more information.\nPrice List # Houdini License Category Interactive Isohedron License Required Price Per Year Commercial (Core/FX) Y iso-hair-1-commercial $200 Commercial (Core/FX) N iso-hair-1-commercial-batch $35 Indie Y iso-hair-1-indie $100 Indie N iso-hair-1-indie-batch $20 Apprentice Y Free to test \u0026mdash; Apprentice N Not supported \u0026mdash; Husk Procedural \u0026mdash; iso-hair-1-procedural $10 All prices in USD Included Batch Licensing Purchases of an interactive license will include a batch license for local hython writes.\nApprentice Licensing Interactive apprentice sessions will not consume a license and is free to use for as long as you\u0026#39;d like. Apprentice batch sessions are disabled.\nContact sales for more information.\n","externalUrl":null,"permalink":"/hair_tools/licenses/","section":"Hair Tools","summary":"","title":"Licenses","type":"hair_tools"},{"content":" force_table_of_contents # This guide covers installing, configuring, and operating the license server — from initial setup through day-to-day administration.\nYou do not need Go, Docker, or any other development tools installed. The server is a single self-contained binary.\nQuick start # Extract the zip and cd into it.\nGet your server ID and send it to your license provider.\n./isohedron-license-server get-server-id Once you receive .lic files, drop them into a licenses/ folder. mkdir -p licenses cp *.lic licenses/ Start the server. ./isohedron-license-server -pubkey public.key The dashboard is at http://localhost:8848. That\u0026rsquo;s it — clients can now check out licenses.\nWhat you should have received # File Description isohedron-license-server The server binary (or isohedron-license-server.exe on Windows) public.key The public key used to verify license files README.md This guide LICENSE.md Software license docker-compose.yml Docker Compose file for running the server in a container .env Configuration for Docker Compose (bind address, port, admin key) You may also have received .lic license files. If not, you\u0026rsquo;ll request them after setting up the server (see Step 4 below).\nSetup # 1. Create a directory for the server # Pick a location on the machine that will run the server. For example:\nLinux/macOS:\nsudo mkdir -p /opt/isohedron-license-server/licenses Windows:\nmkdir C:\\isohedron-license-server\\licenses 2. Copy files into place # Place the binary and public key into the directory:\n/opt/isohedron-license-server/ ├── isohedron-license-server # the binary ├── public.key # the public key └── licenses/ # empty for now — licenses go here later On Linux/macOS, make the binary executable. The licenses/ directory must be writable by the server process (it stores lease data and lock files there):\nchmod +x /opt/isohedron-license-server/isohedron-license-server 3. Choose a port and admin key, then start the server # Port: The server listens on port 8848 by default. Pick a port that isn\u0026rsquo;t used by anything else on this machine. Your license provider may ask for this when creating server-bound licenses.\nAdmin key: Protects administrative operations (releasing stuck seats, purging expired licenses, reloading licenses, shutting down). You make this up yourself — it\u0026rsquo;s just a password you pick. There\u0026rsquo;s no registration or approval process. Pick something long and random:\n# Linux/macOS — generate a random key openssl rand -hex 32 Then start the server:\ncd /opt/isohedron-license-server ./isohedron-license-server \\ -licenses ./licenses \\ -pubkey public.key \\ -addr :8848 \\ -admin-key \u0026#34;an-admin-key-you-make-up\u0026#34; The server will start even without any license files. The dashboard at http://your-server:8848/ will show a warning that no licenses are loaded — that\u0026rsquo;s expected.\nClient applications do not need any key. The signed license files are what controls access.\n4. Request your licenses # Your license provider needs some information from you to create your licenses. Send them the following.\nYour server ID (required for server-bound licenses):\nRun this on the server machine. The ID is a hash unique to this machine and port:\nisohedron-license-server get-server-id # → iso-a7f3b2c1e9d4 If you\u0026rsquo;re using a non-default port, pass --port:\nisohedron-license-server get-server-id --port 9000 # → iso-f5e6d7c8b9a0 Machine details for node-locked licenses (if applicable):\nFor each workstation you want to lock a license to, find its hostname and system ID:\nHostname: run hostname in a terminal on the machine System ID (machine UUID): Linux: cat /etc/machine-id macOS: ioreg -rd1 -c IOPlatformExpertDevice | grep IOPlatformUUID Windows: run in PowerShell: (Get-ItemProperty 'HKLM:\\SOFTWARE\\Microsoft\\Cryptography').MachineGuid Send the hostname and system ID for each machine to your license provider.\n5. Install your licenses # When you receive .lic files from your provider, copy them into the licenses/ directory and tell the server to reload:\ncp *.lic /opt/isohedron-license-server/licenses/ isohedron-license-server reload --admin-key \u0026#34;your-admin-key\u0026#34; The dashboard should now show your licensed products. You can also verify from the command line:\nisohedron-license-server health { \u0026#34;status\u0026#34;: \u0026#34;ok\u0026#34;, \u0026#34;server_version\u0026#34;: \u0026#34;0.1.0\u0026#34;, \u0026#34;license_version\u0026#34;: 1, \u0026#34;min_license_version\u0026#34;: 1, \u0026#34;products\u0026#34;: 1, \u0026#34;leases\u0026#34;: 0 } 6. Run the smoke test # Verify that everything is working end-to-end — checkout, heartbeat, checkin, and cleanup:\nisohedron-license-server test 7. Configure client machines # Client applications only need to know the server URL. Set the appropriate environment variable or configuration for your tool. For example, for Houdini HDAs:\nISOHEDRON_LICENSE_SERVER=http://your-server:8848 No API key is needed on client machines.\n8. Adding more licenses later # Whenever you receive additional .lic files (more seats, new products, renewals):\nCopy the new .lic files into the licenses/ directory. The server automatically detects the change and reloads within 60 seconds. To reload immediately: isohedron-license-server reload --admin-key \u0026#34;your-admin-key\u0026#34; Active sessions are not interrupted. New seats become available immediately.\nConfiguration reference # Flag Default Description -licenses ./licenses Directory containing your .lic files -pubkey public.key Path to the public key file -addr :8848 Address and port to listen on -admin-key (none) Admin key for privileged operations (force-release, purge-expired, reload). You make this up. Alternatively, set ISOHEDRON_ADMIN_KEY_FILE to read the key from a file. -heartbeat 2m How often clients should send heartbeats -ttl 5m How long to wait before reclaiming a seat from a silent client -tls-cert (none) Path to a TLS certificate file (enables HTTPS) -tls-key (none) Path to a TLS private key file (enables HTTPS) CLI commands # The server binary includes built-in commands for managing a running server. You don\u0026rsquo;t need curl or any other tools.\nRelease stuck seats # If a machine\u0026rsquo;s seats are stuck (e.g., after a crash), you can release a specific lease by ID or all leases for a machine:\n# Release a specific lease (get the ID from status) isohedron-license-server force-release \\ --lease-id \u0026#34;a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d\u0026#34; \\ --admin-key \u0026#34;your-admin-key\u0026#34; # Release all leases for a machine isohedron-license-server force-release \\ --product my-product \\ --machine-id \u0026#34;WORKSTATION-A-7a8b9c0d\u0026#34; \\ --admin-key \u0026#34;your-admin-key\u0026#34; Get this server\u0026rsquo;s ID # If your license provider needs to create a server-bound license, they\u0026rsquo;ll ask for your server ID:\nisohedron-license-server get-server-id If you\u0026rsquo;re using a non-default port, include --port:\nisohedron-license-server get-server-id --port 9000 Send the output (e.g., iso-a7f3b2c1e9d4) to whoever creates your licenses.\nCheck server health # Shows whether the server is running, how many products are licensed, and how many active leases there are. Also reports warnings if the licenses directory is missing or no licenses are loaded.\nisohedron-license-server health View loaded licenses # See every license file the server has loaded, including its type, capacity, expiry date, days remaining, and whether it\u0026rsquo;s active or expired. Useful for checking when renewals are needed.\nisohedron-license-server licenses Purge expired licenses # Move expired license files out of the active licenses directory into an expired/ subdirectory. The server reloads automatically afterward.\nisohedron-license-server purge-expired --admin-key \u0026#34;your-admin-key\u0026#34; You can also do this from the dashboard using the Purge Expired button.\nReload license files # After adding new .lic files to the licenses/ directory:\nisohedron-license-server reload --admin-key \u0026#34;your-admin-key\u0026#34; Shut down the server # isohedron-license-server shutdown --admin-key \u0026#34;your-admin-key\u0026#34; View license status # Shows detailed information about each licensed product: how many floating seats are available and in use, how many node-locked machines are configured, who has what checked out, and when licenses expire.\nSee all products:\nisohedron-license-server status See a specific product:\nisohedron-license-server status my-product Run a smoke test # Verify that everything is working — checkout, license proof, response signature, heartbeat, checkin, and cleanup:\nisohedron-license-server test All commands default to http://localhost:8848. To target a remote server, add --server:\nisohedron-license-server status --server http://other-host:8848 Running as a background service # Linux (systemd) # Create /etc/systemd/system/isohedron-license-server.service:\n[Unit] Description=Isohedron License Server After=network.target [Service] ExecStart=/opt/isohedron-license-server/isohedron-license-server \\ -licenses /opt/isohedron-license-server/licenses \\ -pubkey /opt/isohedron-license-server/public.key \\ -addr :8848 \\ -admin-key \u0026#34;an-admin-key-you-make-up\u0026#34; ExecReload=/bin/kill -HUP $MAINPID Restart=on-failure WorkingDirectory=/opt/isohedron-license-server [Install] WantedBy=multi-user.target Then:\nsudo systemctl daemon-reload sudo systemctl enable isohedron-license-server sudo systemctl start isohedron-license-server Check status:\nsudo systemctl status isohedron-license-server View logs:\njournalctl -u isohedron-license-server -f Linux (supervisord) # If you\u0026rsquo;re using Supervisor instead of systemd, create /etc/supervisor/conf.d/isohedron-license-server.conf:\n[program:isohedron-license-server] command=/opt/isohedron-license-server/isohedron-license-server -licenses /opt/isohedron-license-server/licenses -pubkey /opt/isohedron-license-server/public.key -addr :8848 -admin-key \u0026#34;an-admin-key-you-make-up\u0026#34; directory=/opt/isohedron-license-server autostart=true autorestart=true stdout_logfile=/var/log/isohedron-license-server.log stderr_logfile=/var/log/isohedron-license-server.log Then:\nsudo supervisorctl reread sudo supervisorctl update sudo supervisorctl start isohedron-license-server Check status:\nsudo supervisorctl status isohedron-license-server View logs:\ntail -f /var/log/isohedron-license-server.log macOS (launchd) # Create ~/Library/LaunchAgents/com.isohedron.license-server.plist:\n\u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;UTF-8\u0026#34;?\u0026gt; \u0026lt;!DOCTYPE plist PUBLIC \u0026#34;-//Apple//DTD PLIST 1.0//EN\u0026#34; \u0026#34;http://www.apple.com/DTDs/PropertyList-1.0.dtd\u0026#34;\u0026gt; \u0026lt;plist version=\u0026#34;1.0\u0026#34;\u0026gt; \u0026lt;dict\u0026gt; \u0026lt;key\u0026gt;Label\u0026lt;/key\u0026gt; \u0026lt;string\u0026gt;com.isohedron.license-server\u0026lt;/string\u0026gt; \u0026lt;key\u0026gt;ProgramArguments\u0026lt;/key\u0026gt; \u0026lt;array\u0026gt; \u0026lt;string\u0026gt;/opt/isohedron-license-server/isohedron-license-server\u0026lt;/string\u0026gt; \u0026lt;string\u0026gt;-licenses\u0026lt;/string\u0026gt; \u0026lt;string\u0026gt;/opt/isohedron-license-server/licenses\u0026lt;/string\u0026gt; \u0026lt;string\u0026gt;-pubkey\u0026lt;/string\u0026gt; \u0026lt;string\u0026gt;/opt/isohedron-license-server/public.key\u0026lt;/string\u0026gt; \u0026lt;string\u0026gt;-addr\u0026lt;/string\u0026gt; \u0026lt;string\u0026gt;:8848\u0026lt;/string\u0026gt; \u0026lt;string\u0026gt;-admin-key\u0026lt;/string\u0026gt; \u0026lt;string\u0026gt;an-admin-key-you-make-up\u0026lt;/string\u0026gt; \u0026lt;/array\u0026gt; \u0026lt;key\u0026gt;RunAtLoad\u0026lt;/key\u0026gt; \u0026lt;true/\u0026gt; \u0026lt;key\u0026gt;KeepAlive\u0026lt;/key\u0026gt; \u0026lt;true/\u0026gt; \u0026lt;key\u0026gt;StandardOutPath\u0026lt;/key\u0026gt; \u0026lt;string\u0026gt;/opt/isohedron-license-server/server.log\u0026lt;/string\u0026gt; \u0026lt;key\u0026gt;StandardErrorPath\u0026lt;/key\u0026gt; \u0026lt;string\u0026gt;/opt/isohedron-license-server/server.log\u0026lt;/string\u0026gt; \u0026lt;/dict\u0026gt; \u0026lt;/plist\u0026gt; Then:\nlaunchctl load ~/Library/LaunchAgents/com.isohedron.license-server.plist Windows # The simplest approach is to use NSSM (the Non-Sucking Service Manager):\nnssm install IsohedronLicenseServer C:\\isohedron-license-server\\isohedron-license-server.exe nssm set IsohedronLicenseServer AppParameters -licenses C:\\isohedron-license-server\\licenses -pubkey C:\\isohedron-license-server\\public.key -addr :8848 -admin-key \u0026#34;an-admin-key-you-make-up\u0026#34; nssm set IsohedronLicenseServer AppDirectory C:\\isohedron-license-server nssm set IsohedronLicenseServer AppStdout C:\\isohedron-license-server\\server.log nssm set IsohedronLicenseServer AppStderr C:\\isohedron-license-server\\server.log nssm start IsohedronLicenseServer Or run it directly in a terminal:\ncd C:\\isohedron-license-server isohedron-license-server.exe -licenses .\\licenses -pubkey public.key -addr :8848 -admin-key \u0026#34;an-admin-key-you-make-up\u0026#34; Docker Compose # A docker-compose.yml and .env file are included in the distribution. Place them alongside the binary, public key, and licenses directory:\nyour-directory/ ├── .env # configuration (bind address, port, admin key) ├── docker-compose.yml ├── isohedron-license-server # the Linux binary ├── public.key └── licenses/ └── *.lic Edit .env to configure the server:\n# Which interface to accept connections on (0.0.0.0 = all, 127.0.0.1 = localhost only) ISOHEDRON_BIND_ADDRESS=0.0.0.0 # Port to expose on the host ISOHEDRON_PORT=8848 # Admin key for privileged operations (empty = no auth) ISOHEDRON_ADMIN_KEY=an-admin-key-you-make-up # Or read the admin key from a file instead (more secure): # ISOHEDRON_ADMIN_KEY_FILE=/run/secrets/admin-key Then start:\ndocker compose up -d The server is available at http://localhost:8848 (or whichever port you configured). Logs are accessible via docker compose logs -f.\nTo reload licenses after adding new .lic files:\nisohedron-license-server reload --admin-key \u0026#34;your-admin-key\u0026#34; To stop:\ndocker compose down Adding new license files # When you receive additional .lic files (e.g., more seats, new products):\nCopy the new .lic file into the licenses/ directory. The server automatically detects the change and reloads within 60 seconds. If you need the reload to take effect immediately, you can trigger it manually:\nCLI command:\nisohedron-license-server reload --admin-key \u0026#34;your-admin-key\u0026#34; Signal (Linux/macOS only):\nkill -HUP $(pidof isohedron-license-server) systemd (Linux):\nsudo systemctl reload isohedron-license-server Active sessions are not interrupted. New seats become available immediately.\nDashboard # Open http://your-server:8848/ in a browser to see:\nWhich products are licensed and how many seats are available Who currently has a license checked out How many days until the earliest license expires The dashboard updates automatically every 30 seconds. No login is required.\nREST API endpoints # The server exposes a REST API on the configured address (default :8848). Admin endpoints require the X-API-Key header if -admin-key is set.\nAdmin endpoints # Method Path Description POST /v1/admin/force-release Force-release a lease by ID or by machine POST /v1/admin/purge-expired Move expired license files to expired/ subdirectory POST /v1/admin/reload Hot-reload license files from disk POST /v1/admin/shutdown Gracefully shut down the server Informational endpoints # Method Path Description GET / Web dashboard GET /v1/health Health check (includes server version, product/lease counts) GET /v1/licenses List all loaded license files with expiry status GET /v1/metrics Prometheus-format metrics GET /v1/server-id This server\u0026rsquo;s hashed ID (for server-bound licenses) GET /v1/status Query all products, seats, and active leases GET /v1/version Server version See the README for the full API reference, including client integration endpoints (checkout, checkin, heartbeat).\nCommon issues # Server won\u0026rsquo;t start # \u0026ldquo;failed to load public key\u0026rdquo; — The server can\u0026rsquo;t find public.key. Check the path in your -pubkey flag. Server started but no licenses are loaded # \u0026ldquo;no license files found\u0026rdquo; — The licenses/ directory is empty or doesn\u0026rsquo;t contain any .lic files. Make sure your license files have the .lic extension. The server runs without licenses but all checkouts will be denied. \u0026ldquo;skipping license with bad signature\u0026rdquo; — The .lic files were signed with a different key than the public.key you have. Contact whoever provided you with the files. \u0026ldquo;skipping license bound to different server\u0026rdquo; — A .lic file has a server_id that doesn\u0026rsquo;t match this server. Run isohedron-license-server get-server-id to check your server\u0026rsquo;s ID and confirm it matches what was used when the license was created. Clients can\u0026rsquo;t connect # Make sure the server is reachable from client machines (check firewalls, port 8848). Make sure clients are using the correct server URL (e.g., http://your-server:8848). Checkout rejected due to clock skew # \u0026ldquo;server clock appears to be more than 24h behind client\u0026rdquo; — The server\u0026rsquo;s system clock is significantly behind the client machine\u0026rsquo;s clock. This check prevents license expiry bypass. Fix the server\u0026rsquo;s clock (check NTP configuration). A skew of more than 12 hours logs a warning; more than 24 hours rejects the checkout. Seats are stuck / all in use # Crashed clients hold seats until the TTL expires (default: 5 minutes). To see who\u0026rsquo;s holding seats, run:\nisohedron-license-server status The output includes a leases section for each product. Look for the stuck lease:\n{ \u0026#34;products\u0026#34;: [ { \u0026#34;product\u0026#34;: \u0026#34;my-product\u0026#34;, \u0026#34;floating_seats\u0026#34;: 5, \u0026#34;floating_in_use\u0026#34;: 3, \u0026#34;leases\u0026#34;: [ { \u0026#34;lease_id\u0026#34;: \u0026#34;a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d\u0026#34;, \u0026#34;user\u0026#34;: \u0026#34;ben\u0026#34;, \u0026#34;machine_id\u0026#34;: \u0026#34;WORKSTATION-A-7a8b9c0d\u0026#34;, \u0026#34;product\u0026#34;: \u0026#34;my-product\u0026#34;, \u0026#34;lease_type\u0026#34;: \u0026#34;floating\u0026#34;, \u0026#34;checked_out_at\u0026#34;: \u0026#34;2026-05-07T10:00:00Z\u0026#34;, \u0026#34;processes\u0026#34;: { \u0026#34;12345\u0026#34;: {\u0026#34;pid\u0026#34;: \u0026#34;12345\u0026#34;, \u0026#34;last_heartbeat\u0026#34;: \u0026#34;2026-05-07T10:02:00Z\u0026#34;} } } ] } ] } A lease with stale process heartbeats is likely stuck. Free it using its id:\nisohedron-license-server force-release \\ --lease-id \u0026#34;a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d\u0026#34; \\ --admin-key \u0026#34;your-admin-key\u0026#34; Or release all leases for that machine at once:\nisohedron-license-server force-release \\ --machine-id \u0026#34;WORKSTATION-A-7a8b9c0d\u0026#34; \\ --admin-key \u0026#34;your-admin-key\u0026#34; You can also check the dashboard at http://your-server:8848/ which shows the same information visually.\nServer crashed — will I lose active leases? # No. Active leases are saved to .leases inside the licenses directory on every change. When the server restarts, it reloads them. Any leases that expired while the server was down are cleaned up automatically.\nGetting help # If you\u0026rsquo;re seeing errors not covered here, check the server logs. All output is JSON, and the msg field describes what happened:\n# Linux (systemd) journalctl -u isohedron-license-server --since \u0026#34;5 minutes ago\u0026#34; # Linux (supervisord) tail -100 /var/log/isohedron-license-server.log # macOS (launchd) tail -100 /opt/isohedron-license-server/server.log # Docker Compose docker compose logs --since 5m # Windows (NSSM) — if you configured NSSM with log files: nssm get IsohedronLicenseServer AppStdout # Then view that file, or check the Windows Event Viewer under # Applications and Services Logs \u0026gt; IsohedronLicenseServer # Windows (PowerShell) — if running with output redirected to a file: Get-Content C:\\isohedron-license-server\\server.log -Tail 100 # Any platform — just look at the terminal where the server is running ","externalUrl":null,"permalink":"/license_server/documentation/","section":"License Server","summary":"","title":"Operating the License Server","type":"license_server"},{"content":" It seems that the page you\u0026rsquo;ve requested does not exist.\n","externalUrl":null,"permalink":"/error/","section":"Page Not Found","summary":"","title":"Page Not Found","type":"error"},{"content":" Building pipelines that get out of the way # Good pipeline work is invisible. Artists stay in flow, shots move forward, and the infrastructure quietly does its job. When things go wrong it\u0026rsquo;s clear why, and when new work comes in the team is ready for it.\nThat\u0026rsquo;s the standard I hold myself to and what I bring to engagements.\nWhat I do # I work with studios on the design and implementation of Houdini-based pipelines, with a particular focus on USD and Solaris workflows. My background spans both sides of the department wall. I came up through effects work before moving into pipeline. This means I make decisions with artists in mind, not just architecture.\nEngagements typically cover some combination of:\nPipeline design and architecture — high-level workflow design, USD scene structure, department handoff, asset and shot management strategy.\nHoudini tooling — HDAs, artist-facing tools, automation frameworks, submission and rendering pipelines, Solaris/Hydra integration.\nUSD adoption — designing workflows that let artists work naturally without needing to become USD experts themselves.\nInfrastructure and tooling — farm integration, cloud rendering, launcher systems, nightly automation, data management.\nTraining and documentation — upskilling sessions for TDs and artists, code review, pipeline documentation.\nTeam direction — working with leads and stakeholders, providing direction for dev teams, mentoring senior TDs.\nHow I work # I write code intended to be read. That means clear structure, meaningful names, and comments that explain why rather than what. Pipelines outlive their authors, and I want the next person in the seat to understand what they\u0026rsquo;re looking at.\nI prefer to stay close to the artists. The best pipeline decisions come from understanding how work actually moves through a show, and that means talking to the people doing it. I measure the success of a project by whether the department is running better when I leave than when I arrived.\nI\u0026rsquo;m comfortable owning a large scope of work independently, and equally comfortable slotting into an existing team and contributing without disrupting what\u0026rsquo;s already working.\nBackground # Twenty years across effects, animation, and pipeline at studios including Scanline VFX, Luma Pictures, DreamWorks Animation, and Iloura. I have led pipeline teams, architected full department workflows from the ground up, and shipped tools used daily by artists across large productions.\nRecent focus has been on USD-native Houdini pipelines. I design the full stack from scene structure through to delivery, with an emphasis on minimising onboarding friction and maximising the usefulness of production tracking data.\nI also built Isohedron\u0026rsquo;s own pipeline tools out of work done across these studios, so the software on this site reflects actual production experience rather than theoretical design.\nGet in touch # If you\u0026rsquo;re building something new, untangling something that\u0026rsquo;s grown unwieldy, or just want a second opinion on a direction you\u0026rsquo;re considering, I\u0026rsquo;m happy to have a conversation.\ninfo@isohedron.com.au\n","externalUrl":null,"permalink":"/pipeline/","section":"Pipeline Architecture","summary":"","title":"Pipeline Architecture","type":"pipeline"},{"content":"","externalUrl":null,"permalink":"/series/","section":"Series","summary":"","title":"Series","type":"series"},{"content":"","externalUrl":null,"permalink":"/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"Isohedron Tools are a collection of Houdini tools built out of actual production work. They grew from problems I kept running into, solutions I kept rebuilding, and workflows that proved useful enough to be worth sharing properly.\n","externalUrl":null,"permalink":"/home/products/","section":"Homes","summary":"","title":"What We Build","type":"home"},{"content":"The tools on this page came out of real production work and that work is still available directly. Whether you\u0026rsquo;re building a new pipeline from the ground up, untangling one that has grown complicated, or just want a senior set of eyes on a direction you\u0026rsquo;re considering, I\u0026rsquo;d love to help out. Get in touch.\n","externalUrl":null,"permalink":"/home/pipeline/","section":"Homes","summary":"","title":"Working Together","type":"home"}]