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-assetExport
What ships, and how to check it before it does.
Contents
- The drop
- Using it on a site
- PNG and other formats
- Ambient motion
- Size budget
- Asset checks
1. The drop
assetSvg({ width, height, label, body, paper, theme, accents, tint, weight, background, motion, css, id }) from kit/asset.mjs returns one standalone SVG:
ISO_CSS, the ground tokens, the accent rules and the ambient keyframes, inlined in a CDATA<style>.- Every rule beyond the shared kit CSS scoped to the SVG's
id, so two assets inlined on one page don't fight. Give each asset a stableid(the file name is good). width/heightattributes and aviewBox, so it has an intrinsic size in<img>and in design tools.role="img"and anaria-label: say what the object is, in one sentence.- The art in
<g data-art="">, which the preview's safe-zone check measures.
Write it next to the build script with the preview page:
previewHtml shows the SVG inline on its page colour inside a stage the capture, drive and line scripts find by default.
2. Using it on a site
<img src="hero.svg" alt="…">. The default. It renders, scales and animates (CSS animations run inside SVG images), and it caches. Scripts don't run, and the page's CSS can't reach in, which is why everything is inlined.- Inline
<svg>. Paste or import the markup when the page needs to style or script it. The scoped ids keep it from leaking. - React / Next.js.
<img>ornext/imagewithunoptimized(the optimiser rasterises SVG). For an interactive asset, move to Anatomy's React path (references/react.md). - Design tools. Figma and others import the
.svg; they drop CSS variables, so export a flattened copy if the user needs one: open the preview, then save each element's computed fill and stroke (a smalldrive.mjseval), or ship the PNG. - Theme switching. Ship two files (
hero.svg,hero-light.svg) and swap them with<picture>andprefers-color-scheme, or with the site's theme class.
3. PNG and other formats
- PNG at 2×:
node scripts/capture.mjs hero.html --select .asset-stage --scale 2 --out hero@2x.png. The PNG carries the page colour as its background. - Social/OG: build the asset on a 1200 × 630 canvas with
background: true, then capture at--scale 1and--scale 2. - Video or GIF of the ambient loop: capture frames with
drive.mjs(["shot", …]in a loop of["wait", 40]), then assemble with ffmpeg if the user has it. Prefer the SVG itself; a loop that runs in CSS is smaller than any video.
4. Ambient motion
CSS only, so it survives <img>. From kit/asset.mjs:
Rules:
- Every asset moves, and the motion is the object working. A single blinking LED is not enough: give each asset a signature motion someone notices in the first two seconds (rotors spin, a conveyor runs, a needle swings, keys play, ink writes, a pod lowers), plus one or two small echoes (status LEDs, a float). Anything that would turn in real life turns.
- Readable, not busy. At most three or four kinds of motion per asset. Periods 2.5–8 s for slow things, out of phase; spinning things as fast as reads well.
- How to spin a rotor. Get the plane:
topPlane([x, y, z], P)for anything that faces up (an eVTOL rotor, a ducted fan, a ceiling fan), orplaneMatrix(hub, u, v, P)for any other plane, withuandvunit world vectors in it (a wind turbine's rotor:uhorizontal across the rotor,v=[0, 0, -1]; a fan on a box's front face:ualong the face,vdown). Draw the blades in that plane's 2D coordinates around (0, 0):bladesPath(count, r0, r1, { chord, tip, sweep })gives tapered blades to fill with a tone (fill: var(--anatomy-top), ahiormidstroke), and a faint circle at the tip radius reads as the blur disc. Draw the static hub, spinner or grille after it so it covers the blade roots; for a fan behind an opening passclip(the opening's radius in plane units) so the blades never draw outside it. The swept disc sits in one slot of the painter's order: anything that has to pass in front of part of it and behind another part (a tower behind a turbine rotor is fine; a duct lip in front of half the fan needs the fan drawn inside it) must be split around it. - Use
amRotorfor propellers. Bare flat blades turning slowly look like a paper cut-out.amRotoradds what makes a rotor read as spinning: a soft disc (lit with--anatomy-hi, so it is a sheen on dark and a shadow on light), blade thickness, and ghost blades trailing the direction of travel. Wrap it in a material class to colour the blades (carbon, composite). - Speeds. Propellers and fans fast enough to blur: 0.45–0.8 s a turn with
amRotor. A wind turbine slow and stately: 5–7 s,blur: false. Give neighbouring rotors differentdelays (andreverseon alternate ones, as real multirotors counter-rotate) so they don't move in lockstep. - Order never changes. A moving part is drawn in one slot of the painter's order; its whole stroke must keep clear of everything it could pass in front of or behind. If it can't, shorten the stroke or move the part.
- Things that turn spin in their own plane. A CSS
rotateof a drawn part is wrong in an isometric view, but a part that turns in a plane is not: draw it flat in the plane's coordinates andamSpinit (below). Anything with rotors, fans, propellers, turbine blades, wheels seen side-on or a turntable gets this; a static rotor on a hero reads as broken. - Reduced motion. Every
am-*class stops underprefers-reduced-motion: reduce, holding the rest pose. Design the rest pose as the hero frame. - Pass
motion: falsetoassetSvgfor a still drop.
5. Size budget
The synth hero is about 240 KB raw and compresses to a fraction of that with gzip or brotli, which any CDN applies to SVG. Keep a hero under about 400 KB raw and a spot under about 80 KB. If it runs over: fewer facet steps on small cylinders (16–20), fewer dots in grids, and no hidden parts (anything fully covered by a nearer part can go).
6. Asset checks
On top of references/verify.md:
-
xmllint --noout asset.svgis silent. HTML is forgiving;<img>is not: an attribute with no value (<g data-art>) or a stray&renders the whole asset blank. - Loaded through an
<img>it renders and, with motion, moves: write a two-line page with<img src="asset.svg">next to it and capture at two--times. -
capture.mjson the preview printsconsole: clean: nothing in the safe zone. -
lines.mjsprintsline ends: 0, in every theme shipped. - The accent parts at 4×: edges darker (light) or brighter (dark) than their faces, four tones visible, no glare.
- At the size it's shown and at 390 px wide, it still reads as the object.
- With
--reduced, the still frame is the composition you'd choose. - The
aria-labelsays what the object is.