diff --git a/.agents/skills/fixtures/SKILL.md b/.agents/skills/fixtures/SKILL.md
index 953c090a5..d4d6e0207 100644
--- a/.agents/skills/fixtures/SKILL.md
+++ b/.agents/skills/fixtures/SKILL.md
@@ -43,6 +43,13 @@ edge case** that the codebase supports or intends to support. This includes:
filename alone should tell you what's being tested.
- **Labeled specimens.** Within a fixture, label each test case with the
value being exercised so both humans and heuristics can identify regions.
+ Keep labels short, and pin the dimensions of any container holding a
+ label (flex item, grid cell, stretched block) so font-advance-width
+ differences between engines can't leak into box geometry. When a test
+ pipeline offers a text-neutralizing stylesheet (e.g.
+ `fixtures/test-html/_reftest/hide-text.css` for the htmlcss reftests),
+ prefer that over stripping the label — keeping the text helps the next
+ reader understand the fixture.
- **Match the fixture's subject to the viewport policy.** For refbrowser
fixtures under `fixtures/test-html/`, **paint / visual-property**
fixtures should size their root to a preset viewport (via `min-height`)
diff --git a/crates/grida-canvas/src/htmlcss/paint.rs b/crates/grida-canvas/src/htmlcss/paint.rs
index 0f444d728..99da93651 100644
--- a/crates/grida-canvas/src/htmlcss/paint.rs
+++ b/crates/grida-canvas/src/htmlcss/paint.rs
@@ -117,7 +117,7 @@ fn paint_box(
if needs_layer {
let mut layer_paint = Paint::default();
- layer_paint.set_alpha((style.opacity * 255.0) as u8);
+ layer_paint.set_alpha_f(style.opacity);
let has_filter = !style.filter.is_empty();
if has_filter {
if let Some(filter) = build_filter_chain(&style.filter) {
diff --git a/fixtures/test-html/L0/box-padding.html b/fixtures/test-html/L0/box-padding.html
index c74036bef..1e79310ca 100644
--- a/fixtures/test-html/L0/box-padding.html
+++ b/fixtures/test-html/L0/box-padding.html
@@ -14,9 +14,10 @@
}
.label {
+ width: 200px;
+ height: 16px;
font-size: 11px;
color: #666;
- padding-bottom: 4px;
}
.columns {
@@ -28,14 +29,12 @@
.outer {
background: #eee;
- border-radius: 8px;
}
.inner {
background: #000;
- border-radius: 4px;
- font-size: 12px;
- color: #fff;
+ width: 80px;
+ height: 24px;
}
.uniform {
@@ -57,25 +56,25 @@
padding: 8px 32px (horizontal)
padding: 32px 8px (vertical)
padding: 8px 16px 32px 48px
diff --git a/fixtures/test-html/L0/paint-opacity.html b/fixtures/test-html/L0/paint-opacity.html
index e89d7f285..122c3283d 100644
--- a/fixtures/test-html/L0/paint-opacity.html
+++ b/fixtures/test-html/L0/paint-opacity.html
@@ -78,19 +78,19 @@
diff --git a/fixtures/test-html/README.md b/fixtures/test-html/README.md
index c99c1371f..f33610fe5 100644
--- a/fixtures/test-html/README.md
+++ b/fixtures/test-html/README.md
@@ -123,6 +123,27 @@ sides should now be at identical dimensions.
layout changes its natural cull, invalidating `viewport.height` in
the suite. Re-measure and update.
+## Captions and labels
+
+Short captions next to each specimen (`"0.75"`, `"padding: 24px"`,
+etc.) are welcome — they help humans reading the fixture identify what
+each region is testing. Two rules:
+
+- **Keep them short.** The caption is not the subject; if it grows
+ long enough to shape the layout it's in the way.
+- **Don't let captions drive layout.** When captions sit inside flex
+ items, grid cells, or stretched blocks, pin the enclosing element's
+ dimensions (`width`, `height`) so font-advance-width differences
+ between Chromium and cg can't leak into box geometry. Otherwise a
+ 1px shaping difference in "padding: 24px (uniform)" propagates to
+ every following sibling.
+
+When text is incidental (labels, glyph placeholders, captions), inject
+`_reftest/hide-text.css` via the suite's `extra_css` — it neutralizes
+color, text-shadow, and line-height while preserving advance widths
+and block flow. The suite defaults already pull it in; see
+`.agents/skills/cg-reftest/SKILL.md` for details.
+
## Adding a new fixture
1. **Name** — `-[-].html`. The filename is
diff --git a/fixtures/test-html/suites/L0.coverage.json b/fixtures/test-html/suites/L0.coverage.json
index 688fbce4c..8dca76224 100644
--- a/fixtures/test-html/suites/L0.coverage.json
+++ b/fixtures/test-html/suites/L0.coverage.json
@@ -14,7 +14,7 @@
},
{
"path": "../L0/box-padding.html",
- "viewport": { "width": 600, "height": 222 }
+ "viewport": { "width": 600, "height": 256 }
},
{ "path": "../L0/paint-background-solid.html" },
{ "path": "../L0/paint-opacity.html" },
diff --git a/fixtures/test-html/suites/L0.exact.json b/fixtures/test-html/suites/L0.exact.json
index eed77d830..7131aa37f 100644
--- a/fixtures/test-html/suites/L0.exact.json
+++ b/fixtures/test-html/suites/L0.exact.json
@@ -16,6 +16,11 @@
{
"path": "../L0/box-dimensions.html",
"viewport": { "width": 600, "height": 522 }
- }
+ },
+ {
+ "path": "../L0/box-padding.html",
+ "viewport": { "width": 600, "height": 256 }
+ },
+ { "path": "../L0/paint-opacity.html" }
]
}