Skip to content

Follow-up to #1016: finish the paint-inside-your-box contract; evaluate inner-<g> rotation #1129

Description

@talpitoo

Follow-up to #1016 (host clipping + svg { display: block }), which fixed the two overflow classes where they were user-visible. Three remaining items, in descending priority.

1. Four components still have the inline-SVG line-box gap

bearing-indicator, compass-indicator, gauge-horizontal, gauge-vertical render an in-flow inline <svg> with no display: block (audited on develop @ next.122, 2026-08-11 — these are the only four left). Same phantom-height mechanism #1016 fixed for watch, watch-flat and thruster: an inline svg participates in a text line box and reserves ~3–5px of descender space below the graphic, which surfaces as mystery scrollbars / extra height in overflow: auto cells. Their indicator/gauge siblings already carry display: block, so this is aligning stragglers with the established pattern. Expected: zero-pixel snapshot change (the gap is phantom layout height only), as verified for #1016's hunks.

2. One-line docs checklist addition

docs/agents/watch-radial-instruments.md now documents the mechanism ("Host clipping & the arrow-apex shave"), but the new-feature checklist at the bottom doesn't tell the author of a new instrument when the rule applies. Add a checklist line along the lines of: "Rotating an <svg> element box (transform="rotate(...)" on the element)? The host must clip — see Host clipping & the arrow-apex shave." (Edit the source in docs/agents/, then npm run agents:sync.)

3. Decide-by-measurement: inner-<g> rotation refactor

Recording the alternative considered and deliberately not taken in #1016, so it isn't re-discovered later without its trade-offs.

obc-watch (root svg) and obc-compass-sector (overlay svg) are the only two element-box rotations in the codebase. Moving the rotation into an inner <g> would keep the element box axis-aligned, so the svg's own viewport clip would contain all painted content by construction — removing the leak half of the host-clip requirement.

Why it wasn't done in #1016:

  • Identical pixels. The svg viewport edge and the host box edge are the same edge — even the compass-sector arrow-apex shave is unchanged. Zero user-visible improvement.
  • Baseline churn on the most sensitive shared file. Every rotating story risks AA-level shifts that each need review.
  • Open performance question — the reason this item exists. A transform on the svg element is a CSS transform: browsers can update it compositor-side without re-rasterizing vector content. Rotation inside a <g> forces a full SVG re-raster per heading update. With continuously streaming heading data and several instruments per screen on low-power bridge hardware, that difference may be material — or negligible. Nobody has measured it.

Exit criterion: profile both variants under realistic load (several rotating instruments at ~10 Hz heading updates on a low-end target). If inner-<g> is not measurably worse, it's a legitimate hardening refactor to schedule; if it is worse, close this item — the host-clip contract stays the long-term answer (a component never paints outside its box: :host { overflow: hidden }, plus display: block for in-flow svgs).

Context: the "Host clipping & the arrow-apex shave (PR #1016)" section in docs/agents/watch-radial-instruments.md, and the verification comments on #1016.

Metadata

Metadata

Assignees

Type

No type

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions