Emit embeddable chart and graph fragments for hosting in external pages #150

Open
opened 2026-06-28 13:13:52 +02:00 by Brummel · 1 comment
Owner

Context

A LAN documentation server (planned, separate repo) will publish aura's design
docs and embed aura's own charts and graphs inline — using the same render engine
as the CLI, so a strategy graph or an equity curve in the docs is byte-for-byte
what aura graph / aura chart produce, with no second render stack to drift.
That single-source goal requires aura-cli to expose its rendered output in an
embeddable form. Today it can emit only whole, self-contained pages.

Current behaviour (verified)

render_html and render_chart_html (crates/aura-cli/src/render.rs) each
assemble a complete <!doctype html> document; aura graph and
aura chart <name> print it to stdout (pinned by
graph_emits_self_contained_html_viewer and
chart_emits_self_contained_html_for_a_persisted_run in
crates/aura-cli/tests/cli_run.rs). Four properties of that output block
embedding:

  • Whole page. Output is a full <!doctype html></html> document
    (render.rs:98-115, :207-236) — cannot be placed inside a doc page's <body>.
  • Global singletons. Data is injected as window.AURA_MODEL (render.rs:109)
    and window.AURA_TRACES (render.rs:230). Two graphs or two charts on one page
    overwrite each other.
  • Assets inlined per call. Each render inlines the full asset set
    (render.rs:75-81, :103-113, :223-234), including the ~1.4 MB Graphviz-WASM
    blob (assets/viz-standalone.js). N embedded elements ⇒ N copies.
  • Global CSS. SHELL_HEAD sets html, body { … background: #16161a; … }
    (render.rs:24). Embedded as-is, it restyles the entire host page.

What an embedding consumer needs

  • R1 — Fragment output. An output form that is only the embeddable core:
    a container element + its instance-local data + the init call. No
    <!doctype>/<head>/<body>; page chrome (the aura graph / aura chart
    header, breadcrumb, x-mode toggle) optional, not forced.
  • R2 — Collision-free multi-embed. Several charts and/or graphs coexist on
    one page. Data is bound to a unique mount id, not to window; each viewer
    initializes against its own container.
  • R3 — Assets once per page. The viewer assets (uPlot, Graphviz-WASM,
    pan-zoom, the two viewer JS, theme CSS) are loadable once per page as an
    addressable, versioned/hashable bundle, separate from the fragments; fragments
    assume the globals are already present.
  • R4 — Serve-ready data, separate from markup. The consumer can obtain the
    processed data, not the raw trace files: for charts the union-spine-aligned +
    decimated ChartData (xs/series/meta + mode); for graphs the DOT (or model JSON)
    the viewer consumes. The alignment + decimation logic (build_chart_data,
    decimate in crates/aura-cli/src/main.rs) stays aura-internal and must not be
    re-implemented downstream.
  • R5 — Scoped styling. Fragment styles are scoped to the mount container,
    never global html/body rules.
  • R6 — Stable, deterministic contract. The emitted fragment/data format is
    a documented, versioned contract between the two repos; same run/blueprint + same
    aura commit ⇒ byte-identical output (so a downstream mtime cache stays valid).
    aura's C1 determinism already supplies this; the contract inherits it.

Open design questions (for brainstorm)

  • Where the assembly lives. Either aura emits ready-made fragments
    (<div> + <script>), or aura emits only serve-ready data (ChartData JSON /
    DOT) and the consumer owns the fragment template plus the shared viewer assets.
    The latter matches aura's stated role — "aura is a serializer, Graphviz does the
    rest" (render.rs:1-7; docs/design/prototypes/graph-render/README.md) — but
    presupposes the viewer/asset layer is shareable across repos.
  • Graph source addressing. The chart path already names a persisted run
    (aura chart <name>); the graph path renders only the built-in sample
    (aura graph). Addressing a consumer's own blueprint is the separate concern
    already filed as #28, a prerequisite for embedding arbitrary graphs (the chart
    path has no equivalent gap).

Already in place (bounds the lift)

  • Persisted traces under runs/traces/<name>/ are already a documented,
    downstream-consumable columnar-SoA contract: <tap>.json carries
    tap/kinds/ts/columns, index.json carries the RunManifest + ordered
    tap list (pinned by run_trace_persists_columnar_soa_shape_on_disk and
    run_trace_index_carries_manifest_and_ordered_tap_list,
    crates/aura-cli/tests/cli_run.rs).
  • The viewer JS already separates pure logic from the DOM: buildCharts in
    assets/chart-viewer.js is pure (no DOM, no uPlot); the vendored assets live in
    crates/aura-cli/assets/.
  • The whole-page render path is unaffected — this adds an embed mode beside it.

References

  • #28 — expose rendering for a consumer's own graph (graph source addressing;
    prerequisite for arbitrary embedded graphs)
  • #72 — web frontend that drives the aura CLI (related: a different consumer of the
    same render output)
  • #110, #112 — chart decimation refinements (the serve-ready ChartData of R4
    carries the decimated series)
## Context A LAN documentation server (planned, separate repo) will publish aura's design docs and embed aura's own charts and graphs inline — using the same render engine as the CLI, so a strategy graph or an equity curve in the docs is byte-for-byte what `aura graph` / `aura chart` produce, with no second render stack to drift. That single-source goal requires aura-cli to expose its rendered output in an *embeddable* form. Today it can emit only whole, self-contained pages. ## Current behaviour (verified) `render_html` and `render_chart_html` (`crates/aura-cli/src/render.rs`) each assemble a complete `<!doctype html>` document; `aura graph` and `aura chart <name>` print it to stdout (pinned by `graph_emits_self_contained_html_viewer` and `chart_emits_self_contained_html_for_a_persisted_run` in `crates/aura-cli/tests/cli_run.rs`). Four properties of that output block embedding: - **Whole page.** Output is a full `<!doctype html>` … `</html>` document (`render.rs:98-115`, `:207-236`) — cannot be placed inside a doc page's `<body>`. - **Global singletons.** Data is injected as `window.AURA_MODEL` (`render.rs:109`) and `window.AURA_TRACES` (`render.rs:230`). Two graphs or two charts on one page overwrite each other. - **Assets inlined per call.** Each render inlines the full asset set (`render.rs:75-81`, `:103-113`, `:223-234`), including the ~1.4 MB Graphviz-WASM blob (`assets/viz-standalone.js`). N embedded elements ⇒ N copies. - **Global CSS.** `SHELL_HEAD` sets `html, body { … background: #16161a; … }` (`render.rs:24`). Embedded as-is, it restyles the entire host page. ## What an embedding consumer needs - [ ] **R1 — Fragment output.** An output form that is *only* the embeddable core: a container element + its instance-local data + the init call. No `<!doctype>`/`<head>`/`<body>`; page chrome (the `aura graph` / `aura chart` header, breadcrumb, x-mode toggle) optional, not forced. - [ ] **R2 — Collision-free multi-embed.** Several charts and/or graphs coexist on one page. Data is bound to a unique mount id, not to `window`; each viewer initializes against its own container. - [ ] **R3 — Assets once per page.** The viewer assets (uPlot, Graphviz-WASM, pan-zoom, the two viewer JS, theme CSS) are loadable once per page as an addressable, versioned/hashable bundle, separate from the fragments; fragments assume the globals are already present. - [ ] **R4 — Serve-ready data, separate from markup.** The consumer can obtain the *processed* data, not the raw trace files: for charts the union-spine-aligned + decimated `ChartData` (xs/series/meta + mode); for graphs the DOT (or model JSON) the viewer consumes. The alignment + decimation logic (`build_chart_data`, `decimate` in `crates/aura-cli/src/main.rs`) stays aura-internal and must not be re-implemented downstream. - [ ] **R5 — Scoped styling.** Fragment styles are scoped to the mount container, never global `html`/`body` rules. - [ ] **R6 — Stable, deterministic contract.** The emitted fragment/data format is a documented, versioned contract between the two repos; same run/blueprint + same aura commit ⇒ byte-identical output (so a downstream mtime cache stays valid). aura's C1 determinism already supplies this; the contract inherits it. ## Open design questions (for brainstorm) - **Where the assembly lives.** Either aura emits ready-made fragments (`<div>` + `<script>`), or aura emits only serve-ready data (`ChartData` JSON / DOT) and the consumer owns the fragment template plus the shared viewer assets. The latter matches aura's stated role — "aura is a serializer, Graphviz does the rest" (`render.rs:1-7`; `docs/design/prototypes/graph-render/README.md`) — but presupposes the viewer/asset layer is shareable across repos. - **Graph source addressing.** The chart path already names a persisted run (`aura chart <name>`); the graph path renders only the built-in sample (`aura graph`). Addressing a consumer's own blueprint is the separate concern already filed as #28, a prerequisite for embedding arbitrary graphs (the chart path has no equivalent gap). ## Already in place (bounds the lift) - Persisted traces under `runs/traces/<name>/` are already a documented, downstream-consumable columnar-SoA contract: `<tap>.json` carries `tap`/`kinds`/`ts`/`columns`, `index.json` carries the `RunManifest` + ordered tap list (pinned by `run_trace_persists_columnar_soa_shape_on_disk` and `run_trace_index_carries_manifest_and_ordered_tap_list`, `crates/aura-cli/tests/cli_run.rs`). - The viewer JS already separates pure logic from the DOM: `buildCharts` in `assets/chart-viewer.js` is pure (no DOM, no uPlot); the vendored assets live in `crates/aura-cli/assets/`. - The whole-page render path is unaffected — this adds an embed mode beside it. ## References - #28 — expose rendering for a consumer's own graph (graph source addressing; prerequisite for arbitrary embedded graphs) - #72 — web frontend that drives the aura CLI (related: a different consumer of the same render output) - #110, #112 — chart decimation refinements (the serve-ready `ChartData` of R4 carries the decimated series)
Brummel added the feature label 2026-06-28 13:13:52 +02:00
Collaborator

Re-anchoring after cycle #295 (aura-runner/aura-measurement extraction) and the #28 closure — the R1-R6 ask is unchanged and still unaddressed, but two references in this issue are stale and one dependency has cleared:

  1. Line citations have drifted with unrelated edits, not with any fix to the properties they describe. Current locations: render_html spans crates/aura-cli/src/render.rs:86-103 (window.AURA_MODEL injected at line 97); render_chart_html spans crates/aura-cli/src/render.rs:195-221 (window.AURA_TRACES injected at line 218). All four blocking properties (whole-page document, global window singletons, per-call asset inlining, global CSS) remain verified true at these locations.

  2. The 'html, body { background: #16161a; … }' citation at render.rs:24 is stale: SHELL_HEAD (crates/aura-cli/src/render.rs:18-30) now splices its style body from crates/aura-cli/assets/aura.css via include_str! (the #209 single-source-CSS convention). The actual global rule is crates/aura-cli/assets/aura.css:31 (html, body { … background: var(--bg); … }). R5's scoped-styling ask should cite aura.css going forward, not render.rs.

  3. #28, listed here as an open coupled prerequisite ('graph source addressing... the separate concern already filed as #28'), closed 2026-07-10. aura graph <blueprint.json> now renders an arbitrary consumer blueprint (crates/aura-cli/src/main.rs:1859 dispatch_graph, via is_blueprint_file at :1421) — the built-in-sample-only limitation this issue's design-questions section flagged as blocking arbitrary embedded graphs no longer exists. #150's graph path and chart path are now on equal footing; nothing here needs to wait on #28 anymore.

On the open design question ('where the assembly lives'): #28's closing decision (2026-07-10) explicitly dropped a downstream-linkable Rust render crate in favor of keeping the consumer surface CLI-over-blueprint-data ('the ratified consumer surface is CLI-over-blueprint-data… not by linking a Rust render library'). That is a direct precedent for this issue's first open question and leans toward 'aura emits fragments/data via CLI output' over 'consumer links an aura render library' — worth weighing when this is picked up, though it does not by itself pick between R1's two sub-options (ready-made <div>+<script> fragments vs raw ChartData/DOT data for the consumer to template).

Separately, cycle #295 (crates/aura-runner, crates/aura-measurement) established the project's current pattern for CLI-embedded logic a downstream consumer needs: extract it into a library crate reachable without the binary. R4's build_chart_data/decimate (crates/aura-cli/src/main.rs:147, :230) remain private fns inside the CLI binary and were not touched by that extraction — they are a candidate for the same C28-style move if/when this issue is implemented, though that is this issue's call to make, not a prerequisite blocking it.

No change to the R1-R6 requirements or the #72/#110/#112 references; both remain applicable as written.

Re-anchoring after cycle #295 (aura-runner/aura-measurement extraction) and the #28 closure — the R1-R6 ask is unchanged and still unaddressed, but two references in this issue are stale and one dependency has cleared: 1. Line citations have drifted with unrelated edits, not with any fix to the properties they describe. Current locations: render_html spans crates/aura-cli/src/render.rs:86-103 (window.AURA_MODEL injected at line 97); render_chart_html spans crates/aura-cli/src/render.rs:195-221 (window.AURA_TRACES injected at line 218). All four blocking properties (whole-page document, global window singletons, per-call asset inlining, global CSS) remain verified true at these locations. 2. The 'html, body { background: #16161a; … }' citation at render.rs:24 is stale: SHELL_HEAD (crates/aura-cli/src/render.rs:18-30) now splices its style body from crates/aura-cli/assets/aura.css via include_str! (the #209 single-source-CSS convention). The actual global rule is crates/aura-cli/assets/aura.css:31 (`html, body { … background: var(--bg); … }`). R5's scoped-styling ask should cite aura.css going forward, not render.rs. 3. #28, listed here as an open coupled prerequisite ('graph source addressing... the separate concern already filed as #28'), closed 2026-07-10. `aura graph <blueprint.json>` now renders an arbitrary consumer blueprint (crates/aura-cli/src/main.rs:1859 `dispatch_graph`, via `is_blueprint_file` at :1421) — the built-in-sample-only limitation this issue's design-questions section flagged as blocking arbitrary embedded graphs no longer exists. #150's graph path and chart path are now on equal footing; nothing here needs to wait on #28 anymore. On the open design question ('where the assembly lives'): #28's closing decision (2026-07-10) explicitly dropped a downstream-linkable Rust render crate in favor of keeping the consumer surface CLI-over-blueprint-data ('the ratified consumer surface is CLI-over-blueprint-data… not by linking a Rust render library'). That is a direct precedent for this issue's first open question and leans toward 'aura emits fragments/data via CLI output' over 'consumer links an aura render library' — worth weighing when this is picked up, though it does not by itself pick between R1's two sub-options (ready-made `<div>+<script>` fragments vs raw ChartData/DOT data for the consumer to template). Separately, cycle #295 (crates/aura-runner, crates/aura-measurement) established the project's current pattern for CLI-embedded logic a downstream consumer needs: extract it into a library crate reachable without the binary. R4's `build_chart_data`/`decimate` (crates/aura-cli/src/main.rs:147, :230) remain private fns inside the CLI binary and were not touched by that extraction — they are a candidate for the same C28-style move if/when this issue is implemented, though that is this issue's call to make, not a prerequisite blocking it. No change to the R1-R6 requirements or the #72/#110/#112 references; both remain applicable as written.
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Brummel/Aura#150