Help guide

Soft Mesh node

Updated June 21, 2026

Product media placeholder

Replace this area with a screenshot or short walkthrough video during the media sweep.

Sim-only soft-body mesh. F381 P1.1. Owns a verlet ring simulator (edge springs + position-anchored shape match + body wrap/dent + cursor Gaussian press) and emits the deformed mesh through typed graph ports — NOT a sim-handle reference. Renderers consume `vertices`, `subpathStarts`, `sharpFlags`, and `bodyCenterX/Y` to draw the mesh without ever touching the sim object directly (F311 graph-native data flow). **Geometry source** (param `geometrySource`) accepts every kind the meshAttractor catalogue does: `round` / `spike` / `blob` / `svgPath` / `textOutline` / `clipPath` / `rawVertices`. `textOutline` produces multi-glyph rings (one ring per character outer contour with hole topology preserved). All other kinds produce a single ring. Single node handles all rest-shape kinds. **Cursor force gate**: pushes balls within `mouseSigma` of cursor when (a) cursor is in the Gaussian zone of the rest pose AND (b) cursor is moving (smoothing-invariant 6-frame ring activity check, F381 P0.2). Frame walker honours the world's `frameSelector` directly (F381 P0.1) — no `[data-fm-physics-frame]` HTML attribute required.

Type softMeshCategory effectsContext sharedDynamic ports noCompound no

Inputs

PortTypeDescription
worldanyWire from `physicsWorld.world`. Provides the body coord frame + (optional) body coupling handle.
bodyIdsfloatArrayOptional. Engine body handles to test for ball↔mesh contact. Wire from `physicsBodyStagger.bodyIds` for ball-on-mesh interaction. Empty = no body coupling, mesh is purely a cursor-driven visual.
mouseXfloatCursor X in viewport pixels (from `pointer` with `space: viewport`). Triggers Gaussian press on the rings. Unset / NaN = no cursor effect.
mouseYfloatCursor Y in viewport pixels.
geomVerticesfloat32bufferF381 P2.3 — wire from a shared `glyphGeometry` / `shapeGeometry` source to share rest pose with sibling consumers (e.g. `physicsStaticBody{kind:fromGeometry}`). When wired, softMesh uses these buffers instead of building its own from the inline `geometrySource` param — visible mesh + rigid collider are aligned by construction. Wire ALL 3 buffer inputs + `geomBodyCenterX/Y` together; partial wiring throws.
geomSubpathStartsuint16bufferWire from the geometry source's `subpathStarts`. Required when `geomVertices` is wired.
geomRingSubpathCountsuint16bufferWire from the geometry source's `ringSubpathCounts`. Required when `geomVertices` is wired.
geomBodyCenterXfloatWire from the geometry source's `bodyCenterX`. Defines the cursor / render anchor — must match the geometry source's frame of reference. Required when `geomVertices` is wired.
geomBodyCenterYfloatWire from the geometry source's `bodyCenterY`. Required when `geomVertices` is wired.

Outputs

PortTypeDescription
verticesfloat32bufferLive concatenated vertex buffer in body coords [x0,y0,x1,y1,...]. Includes EVERY subpath — outer rings AND holes — in traversal order. Wire into `softMeshRender.vertices`. Allocated once at init, mutated in place per frame (no GC churn).
restVerticesfloat32bufferREST-pose vertex buffer in body coords (same layout as `vertices` — same subpathStarts + sharpFlags apply). Static; written once at init and never mutated. Wire into `softMeshDebugRender.restVertices` for a rest-pose ghost overlay, or any consumer that needs to compare live deformation against the original silhouette.
subpathStartsuint16bufferVertex-pair start index of each subpath (outer rings + holes, flat in traversal order). Wire into `softMeshRender.subpathStarts`. Length = total subpath count.
ringSubpathCountsuint16bufferEntry i = number of subpaths in ring i (1 outer + N holes). First subpath per ring is outer; remaining are holes. Lets consumers like `physicsStaticBody{kind:fromGeometry}` (P2.2) skip hole subpaths when building rigid colliders.
sharpFlagsuint16bufferSharp-corner flag per vertex (1 = sharp `lineTo`, 0 = smooth `quadraticCurveTo`). Wire into `softMeshRender.sharpFlags`.
bodyCenterXfloatSnapshot body-coord X of the rest pose centroid. Renderers translate so this maps to the live host centre — keeps the visual glued to the host element even when the physics frame moves independently (scroll-deck layouts). Wire into `softMeshRender.bodyCenterX`.
bodyCenterYfloatSnapshot body-coord Y of the rest pose centroid. Wire into `softMeshRender.bodyCenterY`.

Parameters

ParameterTypeDefaultDescription
selectorelementSelector""CSS selector for the host element. Used to size the rest pose (auto radius) and resolve the physics frame for cursor coord conversion.
geometrySourcemeshGeometrySource{"kind":"round","segmentCount":32}Pick any geometry kind: round / spike / blob / svgPath / textOutline / clipPath / rawVertices. textOutline produces multi-glyph rings (one ring per character).
radiusfloat-1-1 = auto (~40% of min host dimension). For multi-glyph text, the whole word is refit to fit `2 * radius`.
edgeStiffnessfloat1Per-pass edge-spring relaxation strength. min 0; max 1; step 0.05
constraintIterationsint6Edge-spring + shape-match passes per frame. min 1; max 16
restShapeStrengthfloat0.1Position-anchored shape match. 0 = no recovery (mesh can collapse); 1 = rigid (no deformation). 0.05–0.2 = wobble + readable recovery. min 0; max 1; step 0.01
dampingfloat0.04Verlet damping per step. min 0; max 0.3; step 0.01
gravityScalefloat00 = mesh floats; 1 = falls under world gravity.
bodyRadiusfloat14Treat all incoming bodies as circles of this radius for impulse coupling.
deformZonefloat-1Soft-contact distance from ball centre. Verts within this distance get pulled to the ball surface (curved dent). Should be slightly larger than bodyRadius. -1 = auto.
mouseSigmafloat80Gaussian falloff sigma for cursor displacement.
mouseJumpfloat30Peak cursor displacement at the cursor location. 0 = no cursor effect.
wrapStrengthfloat0.25Per-pass conform aggression. 0 = no wrap (ball appears to float); 1 = instant snap. min 0; max 1; step 0.05
cursorForceScalefloat0.5How strongly the cursor drags in-cursor-zone balls. min 0; max 2; step 0.05
bodyImpulseScalefloat0How aggressively the soft ring kicks balls back on impact. 0 (default) = OFF (rigid colliders handle bounce). Per-pass capped internally so high values don't exceed the engine's CCD budget. min 0; max 2; step 0.05
impactDentScalefloat0.5Velocity-scaled extra dent on impact. 0 = thrown ball deforms same as settled ball. 0.5 = visible squish, recovers via shape match. min 0; max 2; step 0.05
impactDentMaxfloat14Cap on velocity-driven dent depth. min 0; step 1
cornerSharpnessDegfloat25Rest-pose interior turn-angle threshold for sharp corners. 25° works for Inter Black; lower = chunkier silhouette, higher = rounder. min 0; max 90; step 5

Use cases

  • Soft-body letter row — `geometrySource: textOutline` + `softMeshRender`. Cursor presses letters smoothly; balls (via `bodyIds`) dent text on impact.
  • Cursor-reactive blob silhouette — `geometrySource: round/blob/spike` + `softMeshRender`. The cursor presses a deformable blob; no body coupling needed.
  • Logotype micro-interaction — `geometrySource: svgPath` of a logo path + `softMeshRender`. Cursor warps the logo silhouette.

Related nodes

Envelope

Use softMesh as the node type inside a graph node envelope. Add id, optional params, optional connections, and optional activeWhen based on the guide context.

Generated source

Registry faster-motion-docs/node-registry.jsonCategory page /help/faster-motion/faster-motion-node-category-effects/

Was this guide helpful?

Sunny Arora

Written by

Sunny Arora

Get technical deep dives delivered to your inbox

Join creators and developers who get exclusive insights, tutorials, and behind-the-scenes content every week.

No spam. Unsubscribe anytime.

Continue Exploring

You might also enjoy