You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: AGENTS.md
+7-7Lines changed: 7 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -20,7 +20,7 @@ Public API is **mirrored** across React and Vue. Adding a hook on one side witho
20
20
21
21
## Rendering model — the mental model
22
22
23
-
**One visible `Polygon` → one leaf DOM element.** Leaves use canonical CSS primitives where possible and move scale into `matrix3d`; `border-shape` uses a larger fixed primitive because its paint geometry becomes unstable when collapsed to 1px. Textured polygons still pack their local-2D bounding rect (`canvasW × canvasH`) into the atlas. The HTML tag *is* the render strategy — the renderer picks one tag per polygon based on its shape and material.
23
+
**One visible `Polygon` → one leaf DOM element.** Leaves use canonical CSS primitives where possible and move scale into `matrix3d`; clipped solids use fixed primitives because their paint geometry becomes unstable when collapsed to 1px. Textured polygons still pack their local-2D bounding rect (`canvasW × canvasH`) into the atlas. The HTML tag *is* the render strategy — the renderer picks one tag per polygon based on its shape and material.
24
24
25
25
Raw MagicaVoxel `.vox` sources have a narrower baked-mode fast path: `parseVox` still returns the polygon mesh for bounds, fallback rendering, and public handles, but also preserves a `PolyVoxelSource` marker. Eligible vanilla meshes render exact visible voxel quads as hostless `<b>` leaves with canonical `matrix3d(...)` transforms and projected tile4 scanline DOM order. `.vox` normalization snaps to the nearest integer CSS cell size so direct voxel matrices use integer pixel coordinates without any scale wrapper. Brush colors still receive baked Lambert shading from the scene lights. Dynamic lighting, shadows, stable DOM animation, non-exact voxel geometry, and geometry replaced via `setPolygons` fall back to the polygon renderer.
26
26
@@ -30,15 +30,15 @@ Voxel-shaped meshes are the exception to "all polygons stay mounted": meshes wit
30
30
31
31
| Tag | Strategy | When chosen | Paint mechanism | Atlas memory |
32
32
|---|---|---|---|---|
33
-
|`<b>`|**Quads**| Axis-aligned rectangle, or untextured convex quad when the homography passes stability guards |`background: currentColor` on a fixed 64px rectangle; affine and projective quads normalize their `matrix3d` to that primitive, with tiny solid bleed on projective quads to overlap antialias seams | None |
34
-
|`<i>`|**Border-shape clipped solid**| Untextured non-rect on browsers with CSS `border-shape` (Chromium + `pointer:fine` + `hover:hover`) |`border-color: currentColor` on a fixed 64px border-shape primitive, clipped by `border-shape: polygon(...)`; polygon bbox scale and tiny solid bleed are folded into `matrix3d`| None |
33
+
|`<b>`|**Quads**| Axis-aligned rectangle, or untextured convex quad when the homography passes stability guards on non-Safari engines |`background: currentColor` on a fixed 64px rectangle; affine and projective quads normalize their `matrix3d` to that primitive, with tiny solid bleed on projective quads to overlap antialias seams. Safari-family browsers skip the projective quad path and fall through because transformed projective rectangles composite incorrectly there.| None |
34
+
|`<i>`|**Border-shape clipped solid**| Untextured non-rect not caught by the exact corner-shape solid path, on browsers with CSS `border-shape` (Chromium + `pointer:fine` + `hover:hover`) |`border-color: currentColor` on a fixed 16px border-shape primitive, clipped by `border-shape: polygon(...)`; polygon bbox scale and tiny solid bleed are folded into `matrix3d`| None |
35
35
|`<s>`|**Atlas slice**| Textured polygons, or untextured non-rect on browsers without `border-shape`|`background-image` slice of packed bitmap on an auto-budgeted fixed primitive (128px for desktop-class `textureQuality="auto"`, 64px for mobile-class `auto` and explicit numeric quality); atlas position/size and `matrix3d` scale are normalized to the slice, shared textured edges get low-alpha atlas pixels repaired during atlas generation, and solid fallbacks get same-color edge bleed to avoid dark alpha fringes | Bounding-rect area |
36
-
|`<u>`|**Stable solid triangle**|Opt-in for triangles via `renderPolygonsWithStableTriangles` on non-WebKit engines |CSS border-color triangle trick with a fixed canonical 64px border triangle; tiny solid bleed is folded into `matrix3d`. WebKit/Safari falls through to `<s>` because transformed CSS border triangles composite incorrectly there. | None |
36
+
|`<u>`|**Stable solid triangle / corner-shape solid**|Triangles on non-WebKit engines; or untextured non-triangle polygons whose normalized outline is exactly a rectangle with one or more beveled corners on browsers with CSS `corner-shape`| Triangles use a 32px box with two beveled top corners and `background: currentColor` when CSS `corner-shape` support is present, progressively falling back to the CSS border-color triangle trick; exact corner-shape solids use a bare fixed 16px box with inline per-corner radii + `corner-*-shape: bevel` and `background: currentColor`. Tiny solid bleed is folded into `matrix3d`. WebKit/Safari falls through to `<s>` for border triangles because transformed CSS border triangles composite incorrectly there. | None |
37
37
|`<q>`|**Cast shadow leaf**| Per casting polygon when `castShadow: true` and dynamic lighting mode. Applies regardless of caster strategy — `<b>`/`<i>`/`<s>`/`<u>` all produce a `<q>` shadow because only the polygon's outline matters, not its surface. | Same `border-color: currentColor` + `border-shape: polygon(...)` as `<i>`, but transform composes `var(--shadow-proj)` to project the polygon onto the ground plane along the CSS-space light direction | None |
38
38
39
-
Strategies are ordered cheapest → most expensive. The mesher's job is to maximise `<b>` / `<i>` and minimise `<s>` (see "Meshing implications" below).
39
+
Strategies are ordered cheapest → most expensive. The mesher's job is to maximise `<b>` / `<u>` / `<i>` and minimise `<s>` (see "Meshing implications" below).
40
40
41
-
Callers can opt out of specific strategies via `strategies: { disable: ["b" | "i" | "u"] }` on `RenderTextureAtlasOptions`. Disabled or unsupported strategies fall through the chain (`b → i → s`, `u → i → s`, `i → s`). `<s>` is the universal fallback and cannot be disabled.
41
+
Callers can opt out of specific strategies via `strategies: { disable: ["b" | "i" | "u"] }` on `RenderTextureAtlasOptions`. Disabled or unsupported strategies fall through the chain (`b → i → s`, `u → i → s`, `i → s`). Disabling `"i"` also disables the exact corner-shape solid branch even though that branch emits a bare `<u>`, because it belongs to the non-triangle clipped-solid family. `<s>` is the universal fallback and cannot be disabled.
42
42
43
43
The `.vox` fast path emits plain `<b>` elements directly inside the mesh wrapper. They intentionally reuse the cheap quad tag, but they are exact voxel quads with one `matrix3d(...)` per visible quad, ordered by projected tile4 scanline order. Desktop-class documents use a canonical 1px primitive for the cheapest transform shape; mobile-class documents (`pointer: coarse` or `hover: none`) use an 8px primitive and divide the in-plane matrix scale by 8 to preserve identical CSS-space geometry while avoiding large GPU filtering gaps.
44
44
@@ -64,7 +64,7 @@ All solid/atlas tags work in both modes. The `.vox` direct-matrix fast path is b
64
64
65
65
This is the load-bearing constraint behind the whole engine. **JavaScript should not run per-frame to paint polygons when the motion can be expressed as a scene, mesh, camera, or light update.** Once the scene is built and the atlas is rasterised, the browser drives most rendering through CSS — `matrix3d` transforms, `calc()`-driven custom properties, `background-blend-mode`, `border-shape`, etc.
66
66
67
-
The current exception is imported skeletal animation. glTF/GLB skinning changes each polygon independently, so the vanilla stable-DOM animation path samples the active clip in JS, keeps the leaf set mounted, caches baked stable-triangle transform frames, and refreshes baked color on a cadence. That optimized path is the default; do not add a user-facing "baseline vs optimized" toggle or maintain a legacy slow path in product UI.
67
+
The current exception is imported skeletal animation. glTF/GLB skinning changes each polygon independently, so the vanilla stable-DOM animation path samples the active clip in JS, keeps the leaf set mounted, caches baked stable-triangle transform frames, and refreshes baked color on a cadence. On WebKit/Safari, where stable CSS triangles fall through to solid atlas `<s>` leaves, same-topology animation updates keep the existing atlas elements and bitmap URLs mounted, cache transform frames once warmed, and hide briefly degenerate atlas triangles only until the next valid frame. That optimized path is the default; do not add a user-facing "baseline vs optimized" toggle or maintain a legacy slow path in product UI.
0 commit comments