Skip to content
This repository was archived by the owner on May 19, 2026. It is now read-only.
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
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Public API is **mirrored** across React and Vue. Adding a hook on one side witho

| Tag | Strategy | When chosen | Paint mechanism | Atlas memory |
|---|---|---|---|---|
| `<b>` | **Quads** | Axis-aligned rectangle, or untextured convex quad when the homography passes stability guards | `background: currentColor`; canonical quads use a 1px rectangle mapped by `matrix3d` / projective `matrix3d` with tiny solid bleed to overlap antialias seams | None |
| `<b>` | **Quads** | Axis-aligned rectangle, or untextured convex quad when the homography passes stability guards | `background: currentColor`; affine rects use a 1px rectangle mapped by `matrix3d`; projective quads use a bbox-sized rectangle with a normalized high-precision projective `matrix3d` and tiny solid bleed to overlap antialias seams | None |
| `<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 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 a canonical 1px primitive; atlas position/size are normalized to the slice, scale lives in `matrix3d`, and shared textured edges get low-alpha atlas pixels repaired during atlas generation | Bounding-rect area |
| `<u>` | **Stable solid triangle** | Opt-in for triangles via `renderPolygonsWithStableTriangles` | CSS border-color triangle trick with a fixed canonical 1px border triangle; tiny solid bleed is folded into `matrix3d` | None |
Expand Down
13 changes: 8 additions & 5 deletions packages/polycss/src/render/polyDOM.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1300,8 +1300,8 @@ describe("renderPolygonsWithTextureAtlas — strategies.disable", () => {
expect(element.tagName.toLowerCase()).toBe("b");
expect(result.rendered[0].kind).toBe("solid");
expect(style).toContain("transform:matrix3d(");
expect(style).not.toContain("width");
expect(style).not.toContain("height");
expect(style).toContain("width:");
expect(style).toContain("height:");
expect(style).not.toContain("border-shape");
expect(canvases).toHaveLength(0);
result.dispose();
Expand All @@ -1323,16 +1323,19 @@ describe("renderPolygonsWithTextureAtlas — strategies.disable", () => {
{ doc },
);
const matrix = extractMatrix(result.rendered[0].element);
const plan = result.rendered[0].plan!;
const width = plan.canvasW;
const height = plan.canvasH;
const expected = NON_RECT_QUAD.vertices.map((vertex): [number, number, number] => [
vertex[1] * 50,
vertex[0] * 50,
vertex[2] * 50,
]);

expectPointClose(transformMatrixPoint(matrix, 0, 0), expected[0]);
expectPointClose(transformMatrixPoint(matrix, 1, 0), expected[1]);
expectPointClose(transformMatrixPoint(matrix, 1, 1), expected[2]);
expectPointClose(transformMatrixPoint(matrix, 0, 1), expected[3]);
expectPointClose(transformMatrixPoint(matrix, width, 0), expected[1]);
expectPointClose(transformMatrixPoint(matrix, width, height), expected[2]);
expectPointClose(transformMatrixPoint(matrix, 0, height), expected[3]);
result.dispose();
});

Expand Down
14 changes: 10 additions & 4 deletions packages/polycss/src/render/textureAtlas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,8 @@ function computeProjectiveQuadMatrix(
tx: number,
ty: number,
tz: number,
sourceWidth: number,
sourceHeight: number,
guards: ProjectiveQuadGuardSettings,
): string | null {
if (screenPts.length !== 8) return null;
Expand All @@ -518,6 +520,8 @@ function computeProjectiveQuadMatrix(
if (!coeffs) return null;
const { g, h, w1, w3 } = coeffs;
const [q0, q1, , q3] = q;
const sx = Math.max(1, sourceWidth);
const sy = Math.max(1, sourceHeight);

const p0: Vec3 = [
tx + q0[0] * xAxis[0] + q0[1] * yAxis[0],
Expand All @@ -531,11 +535,11 @@ function computeProjectiveQuadMatrix(
];

return formatMatrix3dValues([
...projectiveColumn(q1, w1), g,
...projectiveColumn(q3, w3), h,
...projectiveColumn(q1, w1).map((value) => value / sx), g / sx,
...projectiveColumn(q3, w3).map((value) => value / sy), h / sy,
normal[0], normal[1], normal[2], 0,
p0[0], p0[1], p0[2], 1,
]);
], 6);
}

function formatPercent(value: number, decimals = DEFAULT_BORDER_SHAPE_DECIMALS): string {
Expand Down Expand Up @@ -1524,6 +1528,8 @@ function computeTextureAtlasPlan(
tx,
ty,
tz,
canvasW,
canvasH,
projectiveQuadGuards,
)
: null;
Expand Down Expand Up @@ -2750,7 +2756,7 @@ function createProjectiveSolidElement(
solidPaintDefaults?: SolidPaintDefaults,
): HTMLElement {
const el = doc.createElement("b");
el.setAttribute("style", `transform:matrix3d(${entry.projectiveMatrix})`);
el.setAttribute("style", `width:${formatCssLength(entry.canvasW)};height:${formatCssLength(entry.canvasH)};transform:matrix3d(${entry.projectiveMatrix})`);
applyPolygonDataAttrs(el, entry.polygon);
applySolidPaint(el, entry, textureLighting, solidPaintDefaults);

Expand Down
Loading