Interactive

Hybrid HTML + SVG diagrams from mermoid-ascent: real HTML nodes (click, hover, tooltips), SVG edges/splines that re-layout when the viewport changes. Run sbt docs/specularPreview and work through every section below.

libraryDependencies += "rocks.earlyeffect" %% "mermoid-ascent" % "<version>"   // JVM
libraryDependencies += "rocks.earlyeffect" %%% "mermoid-ascent" % "<version>"  // Scala.js

import mermoid.ascent.MermoidAscent
import mermoid.{Mermaid, RenderConfig, Viewport}

val source = Mermaid("flowchart LR\n  A[Start] --> B[Done]")

MermoidAscent.diagram(source, viewport = Some(Viewport(640)))
MermoidAscent.diagramInteractive(source, initialWidth = 720)

Existing guide pages still embed inert SVG via MermoidAscent.svgDiagram so structure docs stay byte-stable.

Hybrid flowchart

HTML nodes + SVG edges (not an inert SvgNode → UI map). Inspect the DOM: nodes are <button class="mermoid-node">.

MermoidAscent.diagram(hybridFlow, chalkboard, Some(Viewport(640)))
yesno

Hybrid state + notes

States and note cards are HTML; connectors stay in the SVG layer. Click a state or its note.

MermoidAscent.diagramInteractive(stateNotes, chalkboard, initialWidth = 560)
viewport 560px
startpausefinish
Waiting for input

Hover + selection

Click a node: it gets is-selected and incident edges get is-incident. Click again to clear.

MermoidAscent.diagramInteractive(hybridFlow, chalkboard, initialWidth = 640)
viewport 640px
yesno

Tooltips

Mermaid click … "tooltip" becomes an ascent hover card (and SVG <title> on the SVG painter). Hover a node.

MermoidAscent.diagramInteractive(tooltips, chalkboard, initialWidth = 640)
viewport 640px
PaintOpen Early Effect

click C href "…" "…" _blank wraps the node as a link. The Paint node opens earlyeffect.rocks in a new tab.

MermoidAscent.diagram(tooltips, chalkboard, Some(Viewport(640)))
PaintOpen Early Effect

Reactive reflow

Use Narrow / Medium / Wide (or shrink the browser). This example opts into flipDirectionBelow = Some(640): below 640px the layout prefers TB, and at or above 640px it prefers LR. The default config does not flip. Spacing compresses to the viewport. Edges are recomputed, not stretched.

See Responsive layout for direction, spacing compression, and container fit.

MermoidAscent.diagramInteractive(
  reflowWide,
  chalkboard.copy(responsive = ResponsiveConfig(flipDirectionBelow = Some(640))),
  initialWidth = 720,
)
viewport 720px

Scale-to-fit safety

A dense hub still overflows after minimum spacing. Container fit scales the HTML nodes and the SVG edges together, down to the scale floor (default 0.5), then the root scrolls horizontally.

MermoidAscent.diagram(denseFit, chalkboard, Some(Viewport(320)))

Selection across reflow

Select a node, then hit Narrow/Wide: the selected id is preserved while geometry updates.

MermoidAscent.diagramInteractive(reflowWide, chalkboard, initialWidth = 720)
viewport 720px

Theme / chalkboard

Interactive diagram under docs chalkboard colors (Dark base + Early Effect palette).

MermoidAscent.diagramInteractive(hybridFlow, chalkboard, initialWidth = 600)
viewport 600px
yesno

Side-by-side contrast

Same source: inert SVG embed vs hybrid interactive.

SVG (svgDiagram):

MermoidAscent.svgDiagram(hybridFlow, chalkboard)
yesnoStartDecideShipFix

Hybrid (diagramInteractive):

MermoidAscent.diagramInteractive(hybridFlow, chalkboard, initialWidth = 560)
viewport 560px
yesno