← SplineCONTENT HISTORY

Update to Spline

Snapshot Oct 24, 2026 · 13:29 UTC · version 1.2.0

Collection source: downloaded plugin package.

WHAT CHANGED

First saved snapshot

No earlier snapshot is available to establish a change.

Save Spline and check future changes in Following.

Up to 10 plugins free · no card required.

Compare saved observations

Download comparison JSON
Full technical diff · 0 changed fields
Full snapshot data
{
  "description": "The Lathe primitive: revolving a 4-point bezier profile around Y into vases, bottles, bowls, cups, glasses, lamp bases, chess pieces, columns, domes. The points contract (x = radius, y-down, top-first), sizing behavior, segments, open rims & double-siding, profile recipes, and multi-lathe / customMesh fallbacks for complex silhouettes. Load for prompts like \"vase\", \"bottle\", \"bowl\", \"cup\", \"pot\", \"goblet\", \"lathe\".",
  "included_files": [],
  "name": "spline-3d-lathe",
  "skill_md_contents": "---\nname: spline-3d-lathe\ndescription: \"The Lathe primitive: revolving a 4-point bezier profile around Y into vases, bottles, bowls, cups, glasses, lamp bases, chess pieces, columns, domes. The points contract (x = radius, y-down, top-first), sizing behavior, segments, open rims & double-siding, profile recipes, and multi-lathe / customMesh fallbacks for complex silhouettes. Load for prompts like \\\"vase\\\", \\\"bottle\\\", \\\"bowl\\\", \\\"cup\\\", \\\"pot\\\", \\\"goblet\\\", \\\"lathe\\\".\"\n---\n\n# Lathe (profiles of revolution)\n\nA Lathe revolves a 2D profile curve 360° around its vertical (Y) axis — THE\nprimitive for anything a potter or wood-turner could make: vases, bottles,\nbowls, plates, cups, glasses, jars, lamp bases, chess pieces, balusters,\ndomes, bells. Prefer it over stacking spheres/cylinders whenever the object\nis rotationally symmetric with a curved silhouette.\n\n## Create & edit\n\n```\nmesh('Lathe', { points: [[28, -90], [8, -60], [85, 30], [30, 90]] });\ncolor('#c96f4a');\nposition({ y: 90 }); // lift by half the height to sit on a floor\nrename('Vase');\n```\n- `mesh('Lathe', { points?, width?, height?, radius?, segments?,\n  verticalSegments? })` — create. With no params you get the default\n  100-unit egg/barrel profile.\n- `geometry({ ... })` — edit the SELECTED lathe: pass new `points`, or just\n  `width`/`height`/`radius` to rescale the current profile.\n- `get_objects([id])` returns a `lathe` block ({ points, segments,\n  verticalSegments }) in exactly this prop shape — read, tweak, pass back. In\n  the same code block, `select(...)[0].geometry.points` reads it too.\n\n## The points contract (get this right)\n\n`points` is EXACTLY 4 `[x, y]` control points of ONE cubic bezier —\n`[start, handle, handle, end]` — NOT a polyline through 4 positions:\n\n- `x` is the distance from the central axis (the radius). It MUST be >= 0;\n  a negative x is an error.\n- `y` runs DOWNWARD (screen-style, like the editor's 2D curve widget): the\n  most NEGATIVE y is the TOP of the object, the most positive y the bottom.\n- Write the curve from the TOP down (`points[0]` = top, `points[3]` =\n  bottom). A bottom-first profile is the same curve, so the DSL flips it for\n  you — but write top-first so handles read sanely.\n- Units are world units. The DSL recenters the profile vertically (the\n  object's origin becomes the middle of the shape, like every primitive) and\n  keeps `width`/`height`/`depth` synced to the profile's extents, so\n  `get_scene` sizes and the selection box stay true.\n- The middle two points are bezier HANDLES — the curve does not pass through\n  them, it is pulled toward them (a bulge reaches roughly 3/4 of the handle's\n  offset: the default profile's handles sit at x 50 but the real belly radius\n  is 37.5). Sizes are derived from the control hull (handles included),\n  matching the editor's own convention — keep handles inside the silhouette\n  you intend.\n\nEndpoints decide open vs closed:\n- an endpoint AT the axis (`x: 0`) closes that end to a smooth tip/base;\n- an endpoint OFF the axis (`x > 0`) leaves an OPEN circular rim — the\n  surface has zero thickness and no cap. Fine for a floor-hidden base;\n  visible openings (cup/bowl interiors) need `shading({ side: 'double' })`\n  or the inside faces vanish.\n\n## Sizing & smoothness\n\n- `width` (or `radius` = width/2) scales the profile radially; `height`\n  scales it vertically; `depth` is always identical to `width` (it's a\n  revolution). `geometry({ width: 240, height: 400 })` rescales the existing\n  curve — no need to recompute points.\n- `segments` — sides around the axis (default 64). 8–12 + `shading({\n  flatShading: true })` = a faceted, wood-turned low-poly look.\n- `verticalSegments` — subdivisions along the curve (default 64; lower it\n  for low-poly, raise past 64 only for very tall glossy heroes).\n- ANIMATION caveat: geometry size writes do NOT re-render a lathe (the\n  profile drives the surface) — that goes for the bridge's\n  `updateObject({ geometry })` and state/`animate({ geometry: ... })`\n  tweens alike. Animate a lathe with `scale` instead.\n\n## Profile recipes (top-first, y-down)\n\n```\n// Vase — narrow neck, fat belly, planted base (open bottom hidden by floor)\nmesh('Lathe', { points: [[28, -90], [8, -60], [85, 30], [30, 90]] });\n\n// Bowl — wide open rim, rounded closed bottom; double-side the interior\nmesh('Lathe', { points: [[90, -40], [88, 10], [55, 42], [0, 40]] });\nshading({ side: 'double' });\n\n// Bottle — slim straight neck flaring into a straight-walled body\nmesh('Lathe', { points: [[9, -110], [9, -20], [55, -25], [42, 110]] });\n\n// Chess pawn — round head, pinched stem, flared base\nmesh('Lathe', { points: [[0, -70], [45, -70], [0, 20], [40, 70]] });\n```\nIterate like a designer: build, `set_view` + `take_screenshot`, then nudge\nhandles (belly out, neck in) with `geometry({ points })` — small handle moves\nchange the silhouette a lot.\n\n## One bezier is the limit — composing past it\n\nA single cubic can't do a wine glass (bowl + stem + foot) or an ornate\ncolumn. Three escape hatches, in order of preference:\n\n1. STACK LATHES: build each section as its own lathe, align them on the same\n   axis (`position`/`translate` y only), then `group()` — e.g. glass bowl\n   lathe + thin `Cylinder` stem + squat foot lathe.\n2. WALL THICKNESS: a lathe surface is infinitely thin. For a visible-walled\n   vessel, boolean-`subtract` a slightly smaller inner lathe from the outer\n   one (load the `boolean-operations` skill first), or accept\n   `side: 'double'`.\n3. CUSTOM REVOLUTION (`customMesh`): any polyline profile, computed in a\n   loop — rings of vertices around Y, band-triangulated. Use when the\n   silhouette needs more than one curve segment:\n```\n// profile as [radius, y] pairs, TOP first (y-up here — you own the math)\nconst profile = [[0, 160], [30, 150], [12, 120], [12, 40], [55, 20], [60, 0]];\nconst seg = 24;\nconst verts = [];\nconst idx = [];\nfor (let i = 0; i < profile.length; i++) {\n  for (let s = 0; s < seg; s++) {\n    const a = (s / seg) * Math.PI * 2;\n    verts.push(Math.cos(a) * profile[i][0], profile[i][1], Math.sin(a) * profile[i][0]);\n  }\n}\nfor (let i = 0; i < profile.length - 1; i++) {\n  for (let s = 0; s < seg; s++) {\n    const sn = (s + 1) % seg;\n    const top = i * seg;\n    const next = (i + 1) * seg;\n    idx.push(top + s, top + sn, next + s);\n    idx.push(top + sn, next + sn, next + s);\n  }\n}\ncustomMesh({ vertices: verts, indices: idx });\n```\n(Open boundaries render double-sided automatically; see the organic-scenes\nskill for more `customMesh` patterns.)\n\n## Gotchas\n\n- Exactly 4 points, x >= 0, y-down, top-first — the errors tell you which\n  point is wrong; fix that point, don't regenerate everything.\n- A lathe spawns centered at the build center like every mesh: lift it by\n  half its height to sit on a floor.\n- Materials apply to the whole surface — a two-tone vessel (glaze + clay) is\n  two stacked lathes or a gradient/fresnel layer, not two materials.\n- Don't use a lathe for straight-sided prisms — `Cylinder`/`Cone` with\n  taper/corner params are cheaper and rounder-handled there.\n"
}

SHA-256 of public snapshot: ef31148adcb5e1ad56cfa8f76bdb68237c6e390f43f67acc33c5ff48cf815b65