anatomy-asset
Make crafted, highly detailed isometric SVG assets for landing pages, product sites, launch posts, social cards and decks — a hero object, a set of spot illustrations, a feature-tile scene — drawn as real, well-made physical things with many small precise solid parts, four-tone shading, correct painter's order and calm CSS-only ambient motion, mostly monochrome with brand accents. Use this when someone wants a nice-looking illustration, hero image, product visual, spot illustration, icon set, isometric artwork, "Linear-style" or "premium" drawing, or a visual for a section of a site, where the goal is a striking, on-brand picture rather than a diagram that explains how something works. Ships a standalone .svg that works as <img>, inline or in design tools, plus a preview page; can add WebGL shaders or the 3D mode when asked. For interactive figures that explain a technical concept with a live readout, use the anatomy skill instead.
Install
npx skills add https://github.com/Teddarific/skills --skill anatomy-assetReact and Next.js
File layout for one figure
examples/test-rig/ follows this layout. It uses rig.ts, view.ts, geometry.ts, pose.ts, art.tsx, live.tsx and figure.tsx.
The server/client split
- Geometry is pure TypeScript, so it runs on the server and the client receives finished path strings. No geometry code is shipped unless a moving part needs to rebuild per frame. Then
frame.tsis imported bylive.tsxand ships to the client. art.tsxbuilds the static parts as JSX (<Solid paths={BASE_ART.slab} tone="mid" />and so on) and passes them as element props, such asbase,rail,carriageanddial, to the"use client"live component. The live component places them in painter's order and wraps the moving ones in<g ref>.- Only the live component and
kit/react/live.tsxare client code.draw.tsxis server-safe.
The large-page key-warning trap
On a big page the server payload is large, and React streams some element props as deferred (lazy) chunks. The client renders {props.dial} among siblings. It can't mark a lazy as key-checked, so once the lazy resolves to an element without a key, React logs "Each child in a list should have a unique key", pointing at your live component or at IsoFigure. The same figure on a small test page logs nothing, so checking one figure at a time misses it.
There are two fixes, and you should do both from the start:
- Give the root of every element prop a stable key:
const DIAL = (<g key="dial">…</g>), and<React.Fragment key="sled">for fragments. Keys on a single element cost nothing. - Keep
"use client"components out of server-built art. Every client component element inside a server tree becomes a lazy reference, which makes all of its ancestors lazy too. If parts of the art need interactivity (hover-to-highlight, for example), make them plain<g data-part="…">and handle events with delegation in the live component.
Any array you build with .map needs keys as usual.
Styles
- Import
iso.cssonce, globally or in the figure. PutclassName="iso"on a wrapper (or<body>) for the tokens, plusdata-theme="light"for the light theme. - Scope per-figure tokens to the figure's class (
.rig { --rig-glass-top: … }) and override kit tokens inside.iso-plateonly when the card needs it. - Don't put figure tokens on
:root.
Readout
useReadout() finds the nearest .iso-plate [data-readout] from its anchor, and say(text) writes it without re-rendering. Render the resting text on the server so it is right before hydration.
Hydration
Render the rest pose on the server and on the client's first render; start motion only in effects. Don't read window while rendering. asksForStillness() is safe because it is only called inside effects and loops.