Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ Voxel-shaped meshes are the exception to "all polygons stay mounted": meshes wit

| Tag | Strategy | When chosen | Paint mechanism | Atlas memory |
|---|---|---|---|---|
| `<b>` | **Quads** | Axis-aligned rectangle, or untextured convex quad when the homography passes stability guards on non-Safari engines | `background: currentColor` on a fixed 256px 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 |
| `<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 256px border-shape primitive, clipped by `border-shape: polygon(...)`; polygon bbox scale and tiny solid bleed are folded into `matrix3d` | None |
| `<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 |
| `<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 |
| `<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 |
| `<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 256px 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. Firefox uses the same 256px border-triangle primitive to avoid large-perspective compositor banding. Exact corner-shape solids use a bare fixed 256px 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 |
| `<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. Firefox uses a 96px border-triangle primitive to avoid large-perspective compositor banding. Exact corner-shape solids use a bare fixed 32px 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 |
| `<q>` | **Cast shadow leaf** | Per casting polygon when `castShadow: true`, in either 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>`. Dynamic mode chains `var(--shadow-proj)` (driven by `--clx/y/z` + `--shadow-ground-cssz`) so the projection follows the live light vars. Baked mode CPU-bakes the projection into the leaf's inline `matrix3d(...)` and drops back-facing polys from the DOM entirely instead of opacity-gating them. | None |

Strategies are ordered cheapest → most expensive. The mesher's job is to maximise `<b>` / `<u>` / `<i>` and minimise `<s>` (see "Meshing implications" below).
Expand Down
8 changes: 4 additions & 4 deletions packages/core/src/atlas/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ export const DEFAULT_MATRIX_DECIMALS = 3;
export const DEFAULT_BORDER_SHAPE_DECIMALS = 2;
export const DEFAULT_ATLAS_CSS_DECIMALS = 4;
export const DECIMAL_SCALES = [1, 10, 100, 1000, 10000, 100000, 1000000];
export const SOLID_QUAD_CANONICAL_SIZE = 256;
export const SOLID_TRIANGLE_CANONICAL_SIZE = 256;
export const SOLID_TRIANGLE_LARGE_BORDER_CANONICAL_SIZE = 256;
export const SOLID_QUAD_CANONICAL_SIZE = 64;
export const SOLID_TRIANGLE_CANONICAL_SIZE = 32;
export const SOLID_TRIANGLE_LARGE_BORDER_CANONICAL_SIZE = 96;
export const ATLAS_CANONICAL_SIZE_EXPLICIT = 64;
export const ATLAS_CANONICAL_SIZE_AUTO_DESKTOP = 128;
export const BORDER_SHAPE_CENTER_PERCENT = 50;
export const BORDER_SHAPE_POINT_EPS = 1e-7;
export const BORDER_SHAPE_CANONICAL_SIZE = 256;
export const BORDER_SHAPE_CANONICAL_SIZE = 16;
export const BORDER_SHAPE_BLEED = 0.9;
export const CORNER_SHAPE_POINT_EPS = 0.75;
export const CORNER_SHAPE_DUPLICATE_EPS = 0.2;
Expand Down
6 changes: 3 additions & 3 deletions packages/polycss/src/api/createPolyScene.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,11 +426,11 @@ describe("createPolyScene", () => {
expect(styleEl?.textContent).toContain("transform-origin: 0 0");
expect(styleEl?.textContent).toContain("backface-visibility: hidden");
expect(styleEl?.textContent).toContain("background-repeat: no-repeat");
expect(styleEl?.textContent).toContain("width: 256px;");
expect(styleEl?.textContent).toContain("height: 256px;");
expect(styleEl?.textContent).toContain("width: 64px;");
expect(styleEl?.textContent).toContain("height: 64px;");
expect(styleEl?.textContent).toContain("width: var(--polycss-atlas-size, 64px);");
expect(styleEl?.textContent).toContain("height: var(--polycss-atlas-size, 64px);");
expect(styleEl?.textContent).toContain("border-width: 0 128px 256px 128px;");
expect(styleEl?.textContent).toContain("border-width: 0 16px 32px 16px;");
expect(styleEl?.textContent).toContain("width: 0;");
expect(styleEl?.textContent).toContain("height: 0;");
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ describe("solid triangle primitive — corner-bevel vs border", () => {
expect(result).not.toBeNull();
const element = result!.rendered[0].element;
expect(element.className).toBe("");
expect(element.style.borderWidth).toBe("0px 128px 256px");
expect(element.style.borderWidth).toBe("0px 48px 96px");
result!.dispose();
});

Expand Down
2 changes: 1 addition & 1 deletion packages/polycss/src/render/atlas/stableTriangle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { applyPolygonDataAttrs, hasPolygonDataAttrs } from "./emit";
import { resolveSolidTrianglePrimitive } from "./strategy";

const DEFAULT_SOLID_SEAM_BLEED = 1.5;
const SOLID_TRIANGLE_BORDER_WIDTH = "0 128px 256px 128px";
const SOLID_TRIANGLE_BORDER_WIDTH = "0 48px 96px 48px";

type RenderTextureAtlasOptionsWithSeams = RenderTextureAtlasOptions & {
seamBleed?: number;
Expand Down
11 changes: 6 additions & 5 deletions packages/polycss/src/render/polyDOM.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import {

const ATLAS_CANONICAL_SIZE_EXPLICIT = 64;
const ATLAS_CANONICAL_SIZE_AUTO_DESKTOP = 128;
const SOLID_QUAD_CANONICAL_SIZE = 256;
const SOLID_QUAD_CANONICAL_SIZE = 64;
const BORDER_SHAPE_CANONICAL_SIZE = 16;

const CORNER_SHAPE_CORPUS = [
["Bear.glb"],
Expand Down Expand Up @@ -792,8 +793,8 @@ describe("renderPolygonsWithTextureAtlas", () => {
const yScale = Math.hypot(matrix[4], matrix[5], matrix[6]);

expect(element.tagName.toLowerCase()).toBe("i");
expect(xScale).toBeGreaterThan(2 / 256);
expect(yScale).toBeGreaterThan(2 / 256);
expect(xScale).toBeGreaterThan(2 / BORDER_SHAPE_CANONICAL_SIZE);
expect(yScale).toBeGreaterThan(2 / BORDER_SHAPE_CANONICAL_SIZE);
expect(element.style.getPropertyValue("border-shape")).toContain("polygon(");
result.dispose();
});
Expand Down Expand Up @@ -1038,10 +1039,10 @@ describe("renderPolygonsWithTextureAtlas", () => {
expect(element.style.height).toBe("");
expect(element.style.getPropertyValue("--polycss-local-w")).toBe("");
expect(element.style.getPropertyValue("--polycss-local-h")).toBe("");
expect(matrix[0]).toBeGreaterThan(10 / 256);
expect(matrix[0]).toBeGreaterThan(10 / BORDER_SHAPE_CANONICAL_SIZE);
expect(matrix[1]).toBeCloseTo(0, 6);
expect(matrix[4]).toBeCloseTo(0, 6);
expect(matrix[5]).toBeGreaterThan(1 / 256);
expect(matrix[5]).toBeGreaterThan(1 / BORDER_SHAPE_CANONICAL_SIZE);
result.dispose();
});

Expand Down
10 changes: 5 additions & 5 deletions packages/polycss/src/snapshot/exportPolySceneSnapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,8 @@ ${selectorList(features.solidLeafTags)} {
parts.push(`
.polycss-scene b {
background: currentColor;
width: 256px;
height: 256px;
width: 64px;
height: 64px;
}
`);
}
Expand Down Expand Up @@ -402,8 +402,8 @@ ${selectorList(features.solidLeafTags)} {
if (features.leafTags.includes("i")) {
parts.push(`
.polycss-scene i {
width: 256px;
height: 256px;
width: 16px;
height: 16px;
border-color: currentColor;
}
`);
Expand All @@ -427,7 +427,7 @@ ${selectorList(features.solidLeafTags)} {
box-sizing: content-box;
border: 0 solid transparent;
border-color: transparent transparent currentColor transparent;
border-width: 0 128px 256px 128px;
border-width: 0 16px 32px 16px;
}
`);
}
Expand Down
10 changes: 5 additions & 5 deletions packages/polycss/src/styles/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ const CORE_BASE_STYLES = `

.polycss-scene b {
background: currentColor;
width: 256px;
height: 256px;
width: 64px;
height: 64px;
}

.polycss-mesh.polycss-voxel-mesh > .polycss-voxel-face {
Expand Down Expand Up @@ -135,8 +135,8 @@ const CORE_BASE_STYLES = `
}

.polycss-scene i {
width: 256px;
height: 256px;
width: 16px;
height: 16px;
border-color: currentColor;
}

Expand All @@ -152,7 +152,7 @@ const CORE_BASE_STYLES = `
box-sizing: content-box;
border: 0 solid transparent;
border-color: transparent transparent currentColor transparent;
border-width: 0 128px 256px 128px;
border-width: 0 16px 32px 16px;
}

/* <q> — dedicated shadow leaf. Same border-shape rendering trick as <i>
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/scene/atlas/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ describe("updateStableTriangleDom", () => {
};

expect(updateStableTriangleDom(root, [tri])).toBe(true);
expect(leaf.style.borderWidth).toBe("0px 128px 256px");
expect(leaf.style.borderWidth).toBe("0px 48px 96px");
});
});

Expand Down
14 changes: 7 additions & 7 deletions packages/react/src/scene/atlas/solidTriangleStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ export const DEFAULT_AMBIENT_INTENSITY = 0.4;
export const BASIS_EPS = 1e-9;
// Matches the canonical SOLID_TRIANGLE_BLEED constant.
export const SOLID_TRIANGLE_BLEED = 0.75;
const SOLID_TRIANGLE_CANONICAL_SIZE = 256;
const SOLID_TRIANGLE_LARGE_BORDER_CANONICAL_SIZE = 256;
const SOLID_TRIANGLE_LARGE_BORDER_WIDTH = "0 128px 256px 128px";
const SOLID_TRIANGLE_CANONICAL_SIZE = 32;
const SOLID_TRIANGLE_LARGE_BORDER_CANONICAL_SIZE = 96;
const SOLID_TRIANGLE_LARGE_BORDER_WIDTH = "0 48px 96px 48px";
const CORNER_TRIANGLE_STYLE = {
width: "256px",
height: "256px",
width: "32px",
height: "32px",
backgroundColor: "currentColor",
borderWidth: "0",
borderTopLeftRadius: "50% 100%",
Expand Down Expand Up @@ -83,8 +83,8 @@ export function solidTrianglePaintStyle(): CSSProperties | undefined {
export function applySolidTrianglePaintStyle(el: HTMLElement): void {
const primitive = solidTrianglePrimitive();
if (primitive === "corner-bevel") {
el.style.width = "256px";
el.style.height = "256px";
el.style.width = "32px";
el.style.height = "32px";
el.style.backgroundColor = "currentColor";
el.style.borderWidth = "0";
el.style.borderTopLeftRadius = "50% 100%";
Expand Down
6 changes: 3 additions & 3 deletions packages/react/src/styles/styles.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ describe("injectPolyBaseStyles", () => {
expect(el.textContent).toContain("transform-origin: 0 0");
expect(el.textContent).toContain("backface-visibility: hidden");
expect(el.textContent).toContain("background-repeat: no-repeat");
expect(el.textContent).toContain("width: 256px;");
expect(el.textContent).toContain("height: 256px;");
expect(el.textContent).toContain("width: 64px;");
expect(el.textContent).toContain("height: 64px;");
expect(el.textContent).toContain("width: var(--polycss-atlas-size, 64px);");
expect(el.textContent).toContain("height: var(--polycss-atlas-size, 64px);");
expect(el.textContent).toContain("border-width: 0 128px 256px 128px;");
expect(el.textContent).toContain("border-width: 0 16px 32px 16px;");
expect(el.textContent).toContain("width: 0;");
expect(el.textContent).toContain("height: 0;");
});
Expand Down
10 changes: 5 additions & 5 deletions packages/react/src/styles/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ const CORE_BASE_STYLES = `

.polycss-scene b {
background: currentColor;
width: 256px;
height: 256px;
width: 64px;
height: 64px;
}

.polycss-mesh.polycss-voxel-mesh > .polycss-voxel-face {
Expand Down Expand Up @@ -136,8 +136,8 @@ const CORE_BASE_STYLES = `
}

.polycss-scene i {
width: 256px;
height: 256px;
width: 16px;
height: 16px;
border-color: currentColor;
}

Expand All @@ -153,7 +153,7 @@ const CORE_BASE_STYLES = `
box-sizing: content-box;
border: 0 solid transparent;
border-color: transparent transparent currentColor transparent;
border-width: 0 128px 256px 128px;
border-width: 0 16px 32px 16px;
}

/* ── Gizmo override ─────────────────────────────────────────────────────── */
Expand Down
2 changes: 1 addition & 1 deletion packages/vue/src/scene/atlas/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ describe("updateStableTriangleDom", () => {
};

expect(updateStableTriangleDom(root, [tri])).toBe(true);
expect(leaf.style.borderWidth).toBe("0px 128px 256px");
expect(leaf.style.borderWidth).toBe("0px 48px 96px");
});
});

Expand Down
14 changes: 7 additions & 7 deletions packages/vue/src/scene/atlas/solidTriangleStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ export const BASIS_EPS = 1e-9;
const RECT_EPS = 1e-3;
// Matches the canonical SOLID_TRIANGLE_BLEED constant.
export const SOLID_TRIANGLE_BLEED = 0.75;
const SOLID_TRIANGLE_CANONICAL_SIZE = 256;
const SOLID_TRIANGLE_LARGE_BORDER_CANONICAL_SIZE = 256;
const SOLID_TRIANGLE_LARGE_BORDER_WIDTH = "0 128px 256px 128px";
const SOLID_TRIANGLE_CANONICAL_SIZE = 32;
const SOLID_TRIANGLE_LARGE_BORDER_CANONICAL_SIZE = 96;
const SOLID_TRIANGLE_LARGE_BORDER_WIDTH = "0 48px 96px 48px";
const CORNER_TRIANGLE_STYLE = {
width: "256px",
height: "256px",
width: "32px",
height: "32px",
backgroundColor: "currentColor",
borderWidth: "0",
borderTopLeftRadius: "50% 100%",
Expand Down Expand Up @@ -84,8 +84,8 @@ export function solidTrianglePaintStyle(): CSSProperties | undefined {
export function applySolidTrianglePaintStyle(el: HTMLElement): void {
const primitive = solidTrianglePrimitive();
if (primitive === "corner-bevel") {
el.style.width = "256px";
el.style.height = "256px";
el.style.width = "32px";
el.style.height = "32px";
el.style.backgroundColor = "currentColor";
el.style.borderWidth = "0";
el.style.borderTopLeftRadius = "50% 100%";
Expand Down
6 changes: 3 additions & 3 deletions packages/vue/src/styles/styles.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ describe("injectPolyBaseStyles", () => {
expect(el.textContent).toContain("transform-origin: 0 0");
expect(el.textContent).toContain("backface-visibility: hidden");
expect(el.textContent).toContain("background-repeat: no-repeat");
expect(el.textContent).toContain("width: 256px;");
expect(el.textContent).toContain("height: 256px;");
expect(el.textContent).toContain("width: 64px;");
expect(el.textContent).toContain("height: 64px;");
expect(el.textContent).toContain("width: var(--polycss-atlas-size, 64px);");
expect(el.textContent).toContain("height: var(--polycss-atlas-size, 64px);");
expect(el.textContent).toContain("border-width: 0 128px 256px 128px;");
expect(el.textContent).toContain("border-width: 0 16px 32px 16px;");
expect(el.textContent).toContain("width: 0;");
expect(el.textContent).toContain("height: 0;");
});
Expand Down
10 changes: 5 additions & 5 deletions packages/vue/src/styles/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ const CORE_BASE_STYLES = `

.polycss-scene b {
background: currentColor;
width: 256px;
height: 256px;
width: 64px;
height: 64px;
}

.polycss-mesh.polycss-voxel-mesh > .polycss-voxel-face {
Expand Down Expand Up @@ -136,8 +136,8 @@ const CORE_BASE_STYLES = `
}

.polycss-scene i {
width: 256px;
height: 256px;
width: 16px;
height: 16px;
border-color: currentColor;
}

Expand All @@ -153,7 +153,7 @@ const CORE_BASE_STYLES = `
box-sizing: content-box;
border: 0 solid transparent;
border-color: transparent transparent currentColor transparent;
border-width: 0 128px 256px 128px;
border-width: 0 16px 32px 16px;
}

/* ── Dynamic lighting cascade vars (scene root → polygons) ─────────────── */
Expand Down
Loading