{"id":46312,"plugin_id":"plugin_asdk_app_6acd235a70a48191812b3ba9c471b4ac","kind":"skill","collection_source":"plugin_package","comparison_source":null,"observed_at":"2026-10-24T13:29:11.597Z","digest":"9eada71a9470f800689bf2c20dce94e78112cbb2e86664311ac08dc45e6fce47","against":null,"payload":{"description":"Shape Blends (metaballs / SDF blending): melting meshes into ONE smooth organic surface with shapeBlend() — goo, blobs, liquid drops merging, lava lamps, slime, snowmen, clouds, soft cartoon bodies. Creating from member shapes, per-shape union/subtract/intersect, blend range tuning, the resolution budget, children-color gradients, and animating members so the goo morphs. Load for prompts like 'blob', 'goo', 'gooey', 'metaball', 'melt together', 'merge smoothly', 'liquid', 'slime', 'lava lamp', 'organic blend', 'shape blend'.","included_files":[],"name":"spline-3d-shape-blends","skill_md_contents":"---\nname: spline-3d-shape-blends\ndescription: \"Shape Blends (metaballs / SDF blending): melting meshes into ONE smooth organic surface with shapeBlend() — goo, blobs, liquid drops merging, lava lamps, slime, snowmen, clouds, soft cartoon bodies. Creating from member shapes, per-shape union/subtract/intersect, blend range tuning, the resolution budget, children-color gradients, and animating members so the goo morphs. Load for prompts like 'blob', 'goo', 'gooey', 'metaball', 'melt together', 'merge smoothly', 'liquid', 'slime', 'lava lamp', 'organic blend', 'shape blend'.\"\n---\n\n# Shape blends (metaballs / SDF blending)\n\nA Shape Blend melts 2+ meshes into ONE smooth, continuous surface — THE tool\nfor organic soft forms: goo, blobs, merging liquid drops, lava lamps, slime,\nsnowmen, cumulus clouds, soft cartoon bodies, abstract fluid hero shapes.\nWhere a Boolean gives hard, exact CSG edges, a blend SMOOTHS the transition\nbetween shapes over a blend range, like wet clay pressed together. It is\nLIVE: the member meshes become CHILDREN of the Shape Blend container and stay\nfully editable — move/scale/animate a member and the surface re-melts around\nit. Only the blended surface renders; members stop rendering individually.\n\n## Create — ALWAYS two run_code calls\n\nCreate the member meshes first, then combine them in the NEXT call (the\nsame two-call rule as booleans — members created in the same call are not\nbuilt yet, and the alias errors with \"cannot build a shape blend with ...\"):\n\n```\nmesh('Sphere', { width: 220 });\nrename('Body');\nposition({ y: 110 });\nmesh('Sphere', { width: 150 });\nrename('Head');\ntranslate({ y: 150 });\n```\n…then:\n```\nshapeBlend(['Body', 'Head']);\ncolor('#8bd6a8');\nrename('Blob');\n```\n\n- `shapeBlend(target?)` — combine the targeted (or currently selected)\n  meshes into a new Shape Blend. Targets work like `boolean`'s: names, ids,\n  objects from select/mesh, arrays mixing them, or `'all'`. Returns the\n  blend (like `group`) and selects it, so transform/color calls right after\n  target the container.\n- Members join as smooth UNION with the container's global blend range —\n  the right default for goo.\n- Only meshes (and groups of meshes) join; lights and cameras are left\n  where they are. A blend cannot nest inside another blend.\n\n## The two dials that shape the goo\n\n- `blendRange` (container, default 100, world units) — how far shapes melt\n  toward each other. ~0 reads as a hard union; 40–80 is a subtle meniscus;\n  150+ turns separate shapes into one amorphous mass. Shapes further apart\n  than the blend range stay separate blobs — overlap or near-touch is what\n  makes them merge.\n- Distance between members — animate members closer/apart and they visibly\n  merge/split like liquid. This is the whole trick behind lava lamps and\n  drop-merge animations.\n\n## Edit — shapeBlend(props) on the selection\n\nA plain props object edits instead of creating. What it edits depends on\nwhat is selected:\n\n- Container selected (`geometry` type `ShapeBlendGeometry`):\n  ```\n  select(o => o.name === 'Blob');\n  shapeBlend({ blendRange: 60, resolutionLevel: 7, useChildrenColors: true });\n  ```\n  - `blendRange` — the global melt radius (above).\n  - `resolutionLevel` — 5–9 = a 32³…512³ surface field (see the budget\n    below). Default 6.\n  - `useChildrenColors` — false: the container's material paints the whole\n    surface; true: each member's own color blends into a soft gradient\n    across the goo.\n- Member shape selected (a mesh inside the blend):\n  ```\n  select(o => o.name === 'Dent');\n  shapeBlend({ operation: 'subtract' });\n  ```\n  - `operation` — 'union' | 'subtract' | 'intersect'. Subtract carves a\n    soft dent/crater; intersect keeps only the overlap. Switching to\n    subtract automatically tightens that shape to a LOCAL blend range of 25\n    (a crisp-ish carve) unless you pass an explicit `blendRange` with it.\n  - `blendRange` — a NUMBER turns on a per-shape override (this shape melts\n    with its own radius); `'global'` turns the override off again.\n  - `useColor` — for subtract/intersect members when the container uses\n    children colors: whether this shape's color tints the surface.\n- `get_objects([id])` returns a `shapeBlend` block on the container AND on\n  each member in exactly this prop shape — read, tweak, pass back.\n\n## Grow, shrink, dissolve\n\n- ADD a member later: `moveInto('Blob', 'NewShape')` — moving a mesh into\n  the blend (or a group inside it) auto-joins it as a union member.\n- REMOVE a member: `moveInto('root', 'Head')` — moving it out strips the\n  blend params and it becomes an ordinary mesh again.\n- `hide(member)` drops a member's contribution without deleting it — cheap\n  for A/B-ing a shape. `show` melts it back in.\n- `ungroup` does NOT dissolve a Shape Blend (unlike Booleans/groups) — move\n  the members out, then `remove` the empty container.\n- Tree order matters for carving, like booleans: a subtract member carves\n  the shapes BELOW it in the scene tree (members created earlier sit lower).\n  Build the body first, the carvers after.\n\n## Which shapes blend best (and the WebGL caveat)\n\n- `Sphere` (incl. squashed/ellipsoid sizes), `Cube` (cornerRadius honored),\n  `Cylinder` (incl. radiusTop/radiusBottom taper), and `Torus` (incl.\n  partial `arc`) blend ANALYTICALLY — exact and cheapest. PREFER these\n  four; they cover almost every organic build. A cone shape should be a\n  TAPERED CYLINDER (`radiusTop: 0`), not the `Cone` primitive — `Cone` is\n  not one of the analytic four and falls into the mesh-SDF path below.\n- Any OTHER mesh (Lathe, Text, TorusKnot, customMesh, imported models…)\n  joins as a baked mesh SDF — WebGPU only. On the WebGL fallback renderer\n  those members are SKIPPED (the surface renders without them), so a blend\n  built only from the four analytic primitives is the safe, portable\n  choice.\n- Up to 96 shapes per blend. Size members with GEOMETRY params\n  (width/height/depth), not non-uniform `scale` — a member's scale is taken\n  as uniform (only a uniform factor carries into the blend).\n\n## Resolution & the scene-wide budget\n\nThe surface is polygonized from a voxel field; `resolutionLevel` sets its\ndensity: 5 = 32³ (chunky), 6 = 64³ (default), 7 = 128³, 8 = 256³, 9 = 512³.\nLevels cost a SHARED scene budget of 16 points: level 5 = 1, 6 = 2, 7 = 4,\n8 or 9 = 16. So ONE very-high/ultra blend takes the whole budget, and a\nscene fits at most 8 default-level blends. Exceeding it errors — lower an\nexisting blend's `resolutionLevel` or remove one. Stay at the default\nunless the blob is a hero close-up with visible faceting; the field\nre-evaluates live, so high levels cost GPU on every member edit and every\nanimation frame. One blend with 10 members is MUCH cheaper than 10 blends.\n\n## Materials & color\n\n- The blended surface takes the CONTAINER's material: select the blend,\n  then `color`/`shading`/`layer` as usual. Glossy physical shading\n  (`shading({ category: 'physical', roughness: 0.25 })`) sells the liquid\n  look; add a `fresnel` layer for a wet rim.\n- For multi-color goo, color the MEMBERS and turn on\n  `shapeBlend({ useChildrenColors: true })` on the container — colors\n  gradient into each other where shapes melt (classic lava-lamp two-tone).\n\n## Animate the goo\n\nMembers are normal meshes — move them and the surface morphs. Motion is\ncode-driven (# Motion & interactivity; `animation` skill): name the drops,\nthen drive each member's y from the motion document with its OWN frequency\nand phase so the rise/fall reads organic, never mechanical:\n\n```js\n// in the motion document's tick — per drop i, out of sync:\nconst y = drops[i].p.y + Math.sin(t * (0.35 + i * 0.11) + i * 2.2) * 110;\nspline.updateObject(drops[i].id, { position: { y } });\n```\n\nDriving the CONTAINER moves the whole blob as one rigid object (fine for\nfloating/bobbing); driving MEMBERS is what makes it melt and split.\n\n## Recipes\n\n```\n// Lava lamp — two-tone goo rising and falling inside a glass cylinder.\n// Call 1: the drops (varied sizes, stacked) + the glass shell.\n// Call 2: shapeBlend([...drop names]) → blendRange ~120,\n//         useChildrenColors: true; then the motion document drives each\n//         drop's y out of sync (see above).\n\n// Snowman — three stacked spheres, subtle meniscus so it reads hand-packed:\n// Call 1: three spheres, widths 260/190/130, stacked with slight overlap.\n// Call 2: shapeBlend(['Base', 'Middle', 'Head']); shapeBlend({ blendRange: 35 });\n\n// Soft crater / bite — carve a dent that stays smooth:\n// Call 1: the body sphere + a smaller 'Dent' sphere poking into it.\n// Call 2: shapeBlend(['Body', 'Dent']); then\n//         select(o => o.name === 'Dent'); shapeBlend({ operation: 'subtract' });\n```\n\n## Gotchas\n\n- Two run_code calls, always: members must exist BEFORE the call that\n  combines them — \"cannot build a shape blend with ...\" means split the\n  calls, not retry.\n- `mesh('ShapeBlend')` / `add('Mesh', 'ShapeBlendGeometry')` do NOT work —\n  a blend is never created empty; build it FROM its members with\n  `shapeBlend([...])`.\n- Hard-edged mechanical results (windows, drilled holes, machined parts)\n  are BOOLEAN territory — load the boolean-operations skill instead. A\n  blend always rounds and melts.\n- The members' own materials stop rendering (only colors matter, and only\n  with `useChildrenColors`); texture/glass layers belong on the CONTAINER.\n- If the blob looks faceted in a close-up screenshot, raise\n  `resolutionLevel` ONE step and re-check — don't jump straight to 8/9 (it\n  spends the whole scene budget).\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}