Skip to content

fix(visimer): hold the hero headline in place while mermaid renders (PRD-8003) (#3467) - #28

Merged
inkeep-oss-sync[bot] merged 1 commit into
mainfrom
copybara/sync
Aug 13, 2026
Merged

fix(visimer): hold the hero headline in place while mermaid renders (PRD-8003) (#3467)#28
inkeep-oss-sync[bot] merged 1 commit into
mainfrom
copybara/sync

Conversation

@inkeep-oss-sync

Copy link
Copy Markdown

Copybara-translated 1 Inkeep OSS change. Rebase-merge this PR so the prepared commit lands directly on public main.

…PRD-8003) (#3467)

* Hold the hero headline in place while mermaid renders

The visimer.com headline is a live mermaid diagram, so on a cold load the
page went through three states: a plain text headline from index.html for
about 1.3s, then the fully drawn page with a 300px hole where the h1
belongs for another 600ms, then the diagram popping in. The middle state
reads as broken, because the hint line points at an empty band.

The 600ms hole is mermaid pulling its flowchart renderer over two
dynamic imports after React mounts, then laying the diagram out. Rather
than chase that down, close the window: draw a static stand-in headline
that matches the real render and crossfade it out when the real one
lands.

src/hero-diagram.ts is the single definition of both. Its coordinates
are mermaid's own output for the hero source, so the stand-in and the
real diagram share a viewBox and are fitted into the same box by the same
preserveAspectRatio. Measured over the band, the two differ by 0.01% of
pixels at 1440px and 0% at 400px, and the 220ms crossfade covers the
rest.

The same module generates the first-paint markup that a small Vite plugin
inlines into index.html, replacing the hand-maintained copy that used to
live there. That copy carried its own geometry and sat the headline
150px from the top while the real hero puts it at 189px, so mounting
moved the page under the visitor. The hero's layout values now live in
site.css and both renderers read them.

Note that mermaid measures its labels exactly once, and emits a layout
about 2% tighter whenever it happens to render before Inter has loaded.
The committed coordinates are the Inter-loaded ones, which is what a real
visitor gets: the font stylesheet is preconnected and lands well before
the bundle that starts the render.

* Address local review on the hero stand-in

Six items from the review panel, none blocking.

Pass the boot HTML to String.replace as a function rather than a string.
A string replacement gives $&, $' and friends their special meaning, so
the day a hero string gains a dollar sign the served document would be
silently corrupted, and only in the pre-React copy that nobody looks at
during normal development.

Move the last shared strings into hero-diagram.ts: the license label and
the two hint lines were still written out in both renderers, which is the
drift the module exists to prevent. licenseLabel now reads from it, so
the badge and the footer follow one definition.

Link the boot spacer to the real header through a --site-header-h custom
property, with the header enforcing it as a floor. It stays a floor
rather than a fixed height so taller content grows the header instead of
being clipped by it.

Correct the section comment in site.css that still described the old
.mw-svg-host scope. The rules now reach the stand-in too, and a new rule
written to the old scope would style only one of the pair, which is
exactly how the crossfade stops being invisible.

Unexport the two orientation constants, which are only composed into
HERO_PLACEHOLDER_HTML in the same file.

Tighten the comments: drop the point-in-time bundle size and the count of
mermaid's internal imports, name all four inputs the coordinates depend
on so a maintainer tuning heroConfig knows to re-derive them, and use
mermaid's own arrowMarkerPath class on the arrowhead instead of claiming
attribute-level fidelity while diverging on the class name.

Re-verified after the changes: stand-in against the settled render still
differs by 0.01% of band pixels at 1440px and 0% at 400px, hero geometry
is byte-identical, in-place editing works, no console errors.

* Address cloud review on the hero stand-in

Four inline findings and two scope notes from pullfrog, none blocking.

Compose HERO_HEADLINE from the three label constants rather than
restating the sentence. It was the one string in the module still written
twice, so the accessible headline and the visible diagram could drift
apart, which is the duplication the module exists to remove.

Escape the values heroBootHtml interpolates. The JSX consumers of those
same constants get React's escaping; the raw-HTML consumer got none, so
the first hero string to contain a <, an & or a quote would render
correctly in the app and malformed in the served document. Same asymmetry
as the dollar-sign fix, one layer up. Static entities in the template are
markup rather than values and stay as authored.

Stop letting two predicates decide one crossfade. The stand-in's
orientation came from a media query while the diagram's came from a
single mount-time read of window.innerWidth that is deliberately never
re-picked, so resizing across 760px could leave a stacked stand-in fading
into a left-to-right diagram in the same box. The app now renders one
stand-in chosen from the source the editor actually got; the media-query
pair stays, but only in the served document, which has no better option.

Drop the boot block on non-landing routes. index.html is the only entry,
so the landing hero also painted over /playground and /hero-loop until
the bundle routed away from it. Before this change that was a line of
text; a full hero reproduction is worse. An inline synchronous script
removes it during parse, matching main.tsx's own pathname normalization.

Correct the index.html comment that still called this a render-failure
fallback. A failed parse emits render with ok false, which resolves the
gate, fades the stand-in out and reveals the canvas error badge.

Add a dev-only viewBox comparison in the render handler. Nothing else
notices when the hand-measured coordinates stop matching mermaid, and the
only symptom is a stand-in that shifts as it fades on a cold load. It
checks the first render only, since an edited headline is legitimately a
different shape, and import.meta.env.DEV keeps it out of the bundle.

Verified: 0.01% band-pixel difference at 1440px and 0% at 400px unchanged;
/ keeps the stand-in while /playground and /hero-loop drop it; a
1000-to-400 resize after render leaves exactly one stand-in matching the
rendered viewBox; the warning is absent from the production bundle;
in-place editing works with no console errors.
GitOrigin-RevId: c668267a3aef9067cd0392776a7ad61cf3fae633
@inkeep-oss-sync
inkeep-oss-sync Bot merged commit 1747f1f into main Aug 13, 2026
@inkeep-oss-sync
inkeep-oss-sync Bot deleted the copybara/sync branch August 13, 2026 18:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant