epiphany/crates/epiphany-render-svg
Levi Neuwirth 6293734fa0 Agent I-4c: embedded @font-face glyph mode (a second self-contained renderer)
A render mode that references each glyph by its SMuFL codepoint via `<text>`,
drawn from an `@font-face`-embedded Bravura subset, alongside the default inline
`<path>` outlines. The SVG stays self-contained (the font travels in it) and the
text is selectable, at a larger file size.

  - GlyphMode::EmbeddedFont: the SVG declares the font once via
    <defs><style>@font-face{...}</style></defs>, then emits one
    <text transform="translate(x y) scale(1 -1)" font-size="4" ...>&#xNNNN;</text>
    per glyph. Geometry is consistent with PathOutline by construction: same
    origin, a per-glyph counter-flip cancels the outer y-flip, and the SMuFL em is
    four staff spaces. A new `text_count` stat; unbundled glyphs still fall through
    to the visible bbox rect + diagnostic. The metadata comment declares which mode
    produced the SVG (and, on the empty canvas too, via a shared `glyph_note`).
    Path mode stays the byte-golden-locked, pixel-verified reference; the embedded
    mode is structurally tested (well-formed XML — also under `xmllint`; one
    @font-face; one <text>/codepoint per glyph; provenance preserved; determinism).

  - The subset is a GENERATED artifact, not a vendored binary: a deterministic
    base64 OTF emitted into src/font_subset_generated.rs by
    `tools/extract_bravura_outlines.py --font-out` (the same SHA-pinned 1.392 font
    the outlines come from). `recalcTimestamp=False` keeps the source font's fixed
    head.modified so the bytes are reproducible across runs, not just within one.

  - OFL compliance: the subset is a Modified Version, so its PRIMARY font name is
    renamed off the Reserved Font Name "Bravura" to "EpiphanyBravuraSubset" in BOTH
    naming structures an OTF carries — the SFNT `name` table AND the CFF (Name INDEX
    + top-dict FullName/FamilyName). The copyright/trademark/license records, which
    name Bravura as attribution, are kept; the renderer references the renamed
    family in @font-face and <text>. The generator reparses the saved bytes and
    fails if the reserved name leaks into a primary record, and validates the cmap
    covers every glyph.

  - Machine-locked payload: the generator emits the decoded length and a BLAKE3-256
    (the workspace's sole hash) of the font bytes; a render-svg test base64-decodes
    the payload (no new runtime dep) and asserts the length, the OTTO signature, the
    BLAKE3, and — parsing the SFNT name table and CFF Name INDEX — that neither
    primary name is the reserved name. Adds an epiphany-determinism dev-dep.

The demo example gains `--glyph-mode=path|embedded`; lib/README/DECISIONS document
the two modes, the subset's OFL rename, and the regeneration command (--font-out +
the blake3 dependency). PathOutline goldens are byte-unchanged; the outlines stay
byte-identical. Full gate green: build, fmt, clippy, 585 tests, conformance scale 1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 11:09:34 -04:00
..
examples Agent I-4c: embedded @font-face glyph mode (a second self-contained renderer) 2026-06-27 11:09:34 -04:00
src Agent I-4c: embedded @font-face glyph mode (a second self-contained renderer) 2026-06-27 11:09:34 -04:00
tests Agent I-4c: embedded @font-face glyph mode (a second self-contained renderer) 2026-06-27 11:09:34 -04:00
tools Agent I-4c: embedded @font-face glyph mode (a second self-contained renderer) 2026-06-27 11:09:34 -04:00
Cargo.toml Agent I-4c: embedded @font-face glyph mode (a second self-contained renderer) 2026-06-27 11:09:34 -04:00
DECISIONS.md Agent I-4c: embedded @font-face glyph mode (a second self-contained renderer) 2026-06-27 11:09:34 -04:00
README.md Agent I-4c: embedded @font-face glyph mode (a second self-contained renderer) 2026-06-27 11:09:34 -04:00

README.md

epiphany-render-svg

Agent I's SVG renderer behind the Epiphany RenderIR interface (spec Chapter 7): turns a ResolvedLayoutIR into well-formed SVG 1.1, drawing each glyph from genuine Bravura SMuFL data — inline outline <path>s by default (GlyphMode::PathOutline), or <text> set in an @font-face-embedded Bravura subset (GlyphMode::EmbeddedFont). It is the visible end of the v0 Score → layout IR pipeline.

Status

The Score → layout IR → SVG pipeline renders recognizable notation — clefs, noteheads at clef-relative staff positions, accidentals, key/time signatures, rests, barlines, and the staff lines and stems that connect them. Output is golden-locked against both the interface-only stub solver and Agent I's real epiphany-engrave solver (whose horizontal spacing pass re-spaces the glyphs), and the layout round-trip (criterion 6) runs through both. What the renderer itself guarantees, independent of engraving quality: real Bravura glyphs, provenance preserved to the score graph, output XML-valid and deterministic. The renderer consumes any solver's ResolvedLayoutIR.

Demo

# Render a fixture to SVG (stub solver by default):
cargo run -p epiphany-render-svg --example render_fixture -- \
    ten_measure_single_staff > out.svg

# Drive Agent I's engrave solver instead, to bisect renderer-vs-solver:
cargo run -p epiphany-render-svg --example render_fixture -- \
    ten_measure_single_staff --solver=real > out.svg

# Use the embedded-font glyph mode (<text> + @font-face) instead of inline paths:
cargo run -p epiphany-render-svg --example render_fixture -- \
    ten_measure_single_staff --glyph-mode=embedded > out.svg

Fixtures: ten_measure_single_staff, valid_score_rich, valid_score. Stats and diagnostics go to stderr; the SVG goes to stdout.

Library

use epiphany_render_svg::{render, RenderOptions};

let out = render(&resolved_layout_ir, &RenderOptions::default());
assert!(out.is_well_formed());
println!("{}", out.svg);

render is pure and deterministic. RenderOptions controls SVG-encoding choices only (display scale, margin, provenance attributes, and glyph_mode — inline PathOutline vs EmbeddedFont) — nothing that changes engraving.

Bundled Bravura data

Two generated artifacts come from the official OFL Bravura.otf via tools/extract_bravura_outlines.py — the font is not vendored, only the generated Rust is committed:

  • src/outlines_generated.rs — the inline glyph outlines (geometry-only, so byte-stable across fontTools versions);
  • src/font_subset_generated.rs — a base64 OTF subset (just the pipeline's glyphs) for GlyphMode::EmbeddedFont. As a Modified Version, its primary font name is renamed off the Reserved Font Name "Bravura" per the OFL; a content BLAKE3 + decoded length are committed alongside as an integrity lock.

Bravura is © Steinberg Media Technologies GmbH under the SIL Open Font License 1.1 (tools/OFL.txt); both artifacts are redistributed under the same license. To regenerate both (the subset step also needs the blake3 package):

cd crates/epiphany-render-svg/tools
python3 -m venv .venv && . .venv/bin/activate && pip install fonttools blake3
python3 extract_bravura_outlines.py --font-out ../src/font_subset_generated.rs \
    > ../src/outlines_generated.rs