brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
isometric-opsCreate, refine, compose, and export isometric/dimetric assets for web and games: projection math, SVG/CSS/three.js generation, pixel-art and Blender workflows, engine tilemaps, ControlNet AI generation, and the iso-studio composer. Triggers on: isometric, dimetric, tileset, y-sort.
Independent GitHub snapshot · Automated classification · Original documentation governs
Create, refine, compose, and export isometric illustrative assets for websites and games — end to end. This skill covers the exact projection math, the vector/CSS/SVG and three.js generation routes, the pixel-art and Blender pre-render pipelines, engine tilemap integration, the AI-generation-with-structure-control workflow, asset sourcing with licence discipline, and the companion iso-studio scene composer (a standalone app that grew out of this skill). Every constant is derived and machine-checked; every workflow is runnable; every claim is sourced in its reference file.
Boundary — what this skill does NOT own. General three.js / creative-coding scaffolding lives in
genart-ops; app- and game-scale three.js (GLTF pipeline, react-three-fiber,InstancedMesh) lives in thethreejs-opsskill. Colour science and perceptual (OKLCH) ramp construction live incolor-ops.isometric-opsowns only the isometric delta — it cross-links those siblings, it never restates them. Detail lives in the reference files below: this router points, it does not duplicate.
Choose the projection before you draw, generate, or model anything. This is not a deferrable stylistic preference: it fixes the grid math, the tile aspect ratio, the camera rig, and the anti-aliasing strategy for the entire pipeline downstream. Changing it later means re-cutting every asset.
| Job | Projection | Ground-axis angle | Tile / face rule | Where |
|---|---|---|---|---|
| Web / vector illustration, diagrams, icons, hero art | True isometric | 30° (all three axes 120° apart) | all axes foreshorten equally; smooth vector edges ignore pixel stepping | projection-math.md §1, svg-vector-generation.md, css-isometric.md |
| Game tiles, tilemaps, sprite worlds, most "isometric" games | 2:1 dimetric (commonly called isometric in games) | 26.565° = arctan(1/2) | integer 2px:1px steps tessellate; tileW = 2·tileH | projection-math.md §2, coordinates-depth.md, engine-integration.md |
| Hand-placed / library pixel-art primitives (cubes, bricks, slopes) | Pixel-neat 1:2 | 22.6° (obelisk.js pixel-dot pattern) | 1:2 pixel dot stepping avoids staircasing at primitive-drawing level | projection-math.md §7, pixel-art-workflow.md |
The failure mode this prevents. Nearly every "isometric" game is actually dimetric (only two of the three axis separations are equal: ≈116.565°, 116.565°, 126.870°). The trap: an artist draws a "30° isometric" tile, the engine places it on a 2:1 (26.565°) diamond grid, and the tile edges do not meet their neighbours. Small at one tile, catastrophic across a 50×50 map. The fix is not a nudge tool — it is deciding, up front, that game tiles are 2:1 dimetric at 26.565° and writing that number into the tile spec so every asset is cut to the same grid.
Terminology discipline (applies everywhere). On first use per document write "2:1 dimetric (commonly called isometric in games)", then "2:1 dimetric" thereafter. Never call the 2:1 game projection "isometric" unqualified. Distinguish "isometric drawing" (100% scale) from "isometric projection" (81.65% = √(2/3) scale) whenever the distinction affects a measurement.
Machine-emitted by iso-math.py constants; full derivations and
ground-truth checks in projection-math.md.
| Symbol | Exact form | Value | Appears as |
|---|---|---|---|
| Cube tilt ("magic angle") | arctan(1/√2) = arcsin(1/√3) | 35.264° | 3D iso rotation |
| Foreshortening (projection scale) | cos(35.264°) = √(2/3) | 81.65% (0.81650) | true-projection edge scale |
| Isometric drawing scale | full-scale convention | 100% | vector iso (edges read at 100%) |
| True ground angle | definition | 30° | vector iso axes |
| SSR / top-plane squash | cos(30°) | 86.602% (0.86603) | Illustrator scale, 2D plane matrices |
| Figma height / circle→ellipse | tan(30°) | 57.735% (0.57735) | Figma hack, ellipse minor axis |
| CSS back-tip | arctan(√2) = 90° − 35.264° | 54.7356° | CSS rotateX |
| CSS un-foreshorten | √(3/2) = 1/cos(35.264°) | 1.22474 | CSS scale3d |
| Dimetric ground angle | arctan(1/2) | 26.565° | game tiles |
| Dimetric screen slope | tileH/tileW (2:1) | 0.5 | tile-space +x = (+tileW/2, +tileH/2) |
Two Blender ortho-camera rigs, both must appear wherever rigs are discussed: 2:1 dimetric = RotX 60°, RotY 0°, RotZ 45° (cube top 2× wide as tall,
sin 30° = 0.5); true isometric = RotX 54.736°, RotY 0°, RotZ 45° (all three faces equal). Most tutorials use 60/0/45 and mislabel it "isometric" — it is dimetric. Seeblender-prerender.md§1.
Each route is a numbered mini-workflow. Follow the links for the exact numbers, code, and gotchas — the steps here are the spine, the references are the flesh.
For diagrams, icons, hero art, marketing scenes → true isometric (30°).
style-guide.md).css-isometric.md and
svg-vector-generation.md.transform-style: preserve-3d on the container, per-face children,
then the outer stack rotateX(54.7356deg) rotateZ(-45deg) scale3d(1.22474,…) — the
scale goes on the container only (or faces double-scale). 2D affine for flat cards:
the rotate(-30deg) skewX(30deg) scaleY(0.866) recipe family, derived per plane in
css-isometric.md.@elchininet/isometric
(SVG-native, planes/paths) or hand-roll diamond/cube/prism paths using the plane
matrix() recipes (Top matrix(0.86603, 0.5, 0.86603, -0.5, 0, 0), etc.). Grab a
ready grid from assets/grids/ or emit one with
iso-math.py grid-svg.svg-vector-generation.md §7).playwright-ops; tie the render back to the
style checklist.For tilemaps and sprite worlds → 2:1 dimetric (26.565°). This is the discipline route; skipping the spec is how sets drift.
tile-spec.md and pin: projection + exact angle, tile W×H
(W = 2H), unit elevation (px per z-step), anchor at the feet, footprint grammar
(1×1, 2×1, 2×2…), transparent margin/bleed, palette tokens, one light direction, output
format, name_direction_variant.png naming, and scale grammar (one human = N tiles).pixel-art-workflow.md),
pre-render from 3D (Route D), or AI-generate (Route C). Every asset obeys the spec's
numbers.uv run scripts/tile-validate.py --tile-w 64 --tile-h 32 tiles/*.png — flags dimension
drift, alpha halos, edge-bleed, off-centre anchor, palette overflow (exit 10 on any
violation). Every spec line maps to a check
(tile-spec.md "How the spec feeds tile-validate.py").uv run scripts/sheet-pack.py tiles/ --trim --padding 2 --pot → one sheet PNG + a JSON
atlas. An atlas turns N texture binds into 1 — the single biggest win for tile-heavy
scenes (coordinates-depth.md §11).TileMapLayer (Shape=Isometric, Layout=Diamond
Down, Y-Sort on, origin at feet), Unity orthographic checklist, or Phaser/PixiJS manual
cart↔iso. Atlas anchor/pivot mapping is spelled out in
engine-integration.md.(x+y, z, layer, zBias) depth
sort with anchor-at-feet — lives in coordinates-depth.md
and is mirrored by iso-math.py to-screen / to-tile (round-trip verified).Model by output type, scaffolded prompts, ControlNet structure control, refine, vectorize, licence check: task-routes.md.
Ortho rig per projection, bake N-direction sprites (Blender or three.js), re-enter Route B at validate: task-routes.md.
Snap-grid staging, automatic depth sort, PNG/scene-JSON export, blockout to ControlNet in the standalone app: iso-studio.md.
CC0 first, then marketplaces; verify plan, licence and AI-training clause before delivery: task-routes.md.
All scripts follow the Skill Resource Protocol:
stdout = data only, semantic exit codes, --help with EXAMPLES, --json envelopes.
Pure-stdlib scripts run with python; Pillow scripts use PEP 723 inline metadata via
uv run (on this Windows machine avoid the Store python3 stub — it exits 49).
| Script | What it does | Launch |
|---|---|---|
iso-math.py | Canonical constants, tile↔screen transforms, SVG grids, CSS/SVG/Illustrator/Figma transform recipes | python scripts/iso-math.py constants --projection true --json · … to-screen 3 2 --tile-w 64 --tile-h 32 · … grid-svg --projection dimetric21 --tile-w 64 --extent 8 > grid.svg · … transforms --target css-3d |
tile-validate.py | QA gate for (especially AI) tiles: dimension, alpha-halo, edge-bleed, anchor, palette checks; exit 10 on violation | uv run scripts/tile-validate.py --tile-w 64 --tile-h 32 tiles/*.png |
sheet-pack.py | Pack a tiles directory into a spritesheet PNG + JSON atlas; --trim --padding N --pot, deterministic order | uv run scripts/sheet-pack.py tiles/ --trim --padding 2 --pot |
check-iso-facts.py | §7 staleness verifier: --offline asserts constants + reference citations; --live npm-checks named packages (exit 7 advisory / 10 drift) | python scripts/check-iso-facts.py --offline |
| Asset | What it is | Use |
|---|---|---|
prompt-library.md | Ready-to-paste prompt scaffolds by target tool (city block, room cutaway, floating island, warehouse, control room, dashboard, sprite tileset, icon) + universal negative block + Midjourney/Firefly/Recraft/Flux cheatsheets | Route C, step 2 |
palettes/three-tone-presets.json | 8 three-tone presets (kenney-prototype-grey, pastel-dollhouse, industrial-muted, cyberpunk-teal-violet, blueprint, earthy-game, mono-ink, brand-neutral); top-lightest verified by WCAG luminance | Route A/B, style-guide.md |
grids/ | Pre-generated true-iso-{32,64,128}.svg and dimetric-2to1-{32,64,128}.svg (line slope 0.5 dimetric / tan30° true iso) | Route A, backdrops |
blender-iso-rig.py | Headless Blender ortho-rig + N-direction sprite baker + optional depth/normal passes | Route D, step 2 |
| iso-studio (external) | The zero-dependency scene composer — standalone repo at github.com/0xDarkMatter/iso-studio, owns scene-schema.json + the asset library; pointer: iso-studio.md | Route E, §5 |
Standalone zero-dependency app (github.com/0xDarkMatter/iso-studio), run with node <iso-studio>/server.mjs. Palettes, blockout mode, manual pointer: iso-studio.md.
| # | Footgun | Fix | Reference |
|---|---|---|---|
| 1 | Mislabelled dimetric — calling 2:1 game tiles "isometric" and cutting them to a 30° grid; tiles don't tessellate | Game tiles are 2:1 dimetric at 26.565°; write the exact angle into the tile spec | projection-math.md §2/§4, tile-spec.md |
| 2 | Skew without scale — shearing a flat asset onto the iso axes but skipping the cos(30°)=0.86603 vertical scale; right axes, wrong height, won't stack | Run the full Scale → Shear → Rotate; build on the iso plane, never skew-and-call-it-done | projection-math.md §3.2/§3.3 |
| 3 | Centre anchors break y-sort — a tall sprite's centre is high on screen, so a centre-based sort draws it behind nearer objects | Anchor every sprite at its visual feet (ground contact); the sort key uses the tile it stands on | coordinates-depth.md §8 |
| 4 | Elevation folded into the depth key — using x+y+z makes a tall near object sort behind a short far one | z is a tie-breaker after (x+y), never added into it: (x+y, z, layer, zBias) | coordinates-depth.md §5/§7 |
| 5 | Unity near-clip clipping — default near plane hides geometry behind the ortho camera on the XZ map | Push near clip to a large negative (−1000+); Stable Fit → Close Fit shadows; disable cascades | engine-integration.md §2 |
| 6 | Ortho frustum not recomputed on resize — the iso view stretches when the viewport changes | Recompute aspect-scaled left/right/top/bottom in the resize handler; update the projection matrix | threejs-orthographic.md §3 |
| 7 | AI halo edges — semi-transparent fringe around AI-generated tiles that shows as a seam | Alpha-threshold / defringe; tile-validate.py flags halo % mechanically | ai-refinement.md §3 |
| 8 | Licence AI-training clause — "commercial use OK" is not "dataset use OK"; DrawKit forbids AI training | Verify plan + licence + AI-training clause before client delivery | asset-sourcing.md |
| 9 | Flux-dev LoRA licences — Flux.1-dev derivatives are non-commercial; shipping them in a client project is a violation | Check each LoRA's licence flag; prefer permissively-licensed adapters for commercial work | ai-generation.md §2/§7 |
| 10 | Staircasing & the >4× upscale trap — 30° lines staircase in pixel art; pushing an upscaler past 4× invents perspective-breaking detail | Commit to 2:1 pixel-neat stepping; above 4× regenerate at a higher base, don't upscale | pixel-art-workflow.md §1, ai-refinement.md §1 |
genart-ops (general three.js / creative coding) ·
threejs-ops (app/game-scale three.js: GLTF, r3f, InstancedMesh) ·
color-ops (colour science, OKLCH ramps) ·
frontend-design (Claude-Code-bundled; production UI craft) ·
playwright-ops (headless render verification).