SMIL Animation
kUML can render any state machine or BPMN process diagram as an animated SVG — a single file that plays back the model’s execution trace in the browser or any SVG viewer. No JavaScript, no external assets: the animation is pure SMIL, embedded directly in the SVG.
Quick start
# 1. Run the state machine and capture the trace
kuml simulate order-lifecycle.kuml.kts \
--events events.json \
--output order-lifecycle.trace.json
# 2. Render the animated SVG
kuml render order-lifecycle.kuml.kts \
--animated --trace order-lifecycle.trace.json \
--format svg \
--output order-lifecycle-animated.svg
Open the resulting file in any modern browser — the token moves through the diagram according to the captured trace.
The same workflow works for BPMN:
kuml simulate membership-process.kuml.kts \
--events member-events.json \
--output membership.trace.json
kuml render membership-process.kuml.kts \
--animated --trace membership.trace.json \
--format svg
Trace format (kuml.trace.v1)
The trace file is a JSON document produced by kuml simulate. It is the single source
of truth for the animation — the renderer reads the trace and derives all timing from
it without running the machine again.
{
"schema": "kuml.trace.v1",
"machine": "Order",
"entries": [
{"type": "Initialised", "vertex": "start"},
{"type": "Transitioned", "trigger": null, "from": "start", "to": "draft"},
{"type": "Entered", "vertex": "draft"},
{"type": "EventReceived", "event": {"name": "confirm"}},
{"type": "Transitioned", "trigger": "confirm", "from": "draft", "to": "confirmed"},
{"type": "Exited", "vertex": "draft"},
{"type": "Entered", "vertex": "confirmed"},
{"type": "Terminated"}
]
}
For BPMN, the relevant entry types are TokenPlaced, TokenConsumed, and
DecisionTaken. These map to token circle animations along sequence-flow paths.
Read traces programmatically with:
val traceFile = KumlRuntimeJson.decodeFromString(TraceFile.serializer(), json)
Animation elements
| Diagram type | Animation elements |
|---|---|
UML State Machine |
Highlight overlay |
SysML 2 STM |
Same overlay scheme as UML STM — |
UML Activity |
Token |
BPMN Process |
Token |
Per ADR-0014, <animateColor> is never emitted — <animate attributeName="fill">
is used instead (deprecated in SVG 1.2, removed in SVG 2.0).
|
Speed control
Scale the entire timeline with --speed:
kuml render machine.kuml.kts \
--animated --trace trace.json \
--speed 2.0 \
--output fast.svg
SpeedFactor is type-safe — values < 0.1 or > 20.0 are rejected with a clear error.
The default speed factor is 1.0.
Exporting to APNG, WebP, or MP4
An animated SVG can be transcoded to a self-contained animated file with --format:
kuml render order-lifecycle.kuml.kts \
--animated --trace order-lifecycle.trace.json \
--format apng
kuml render order-lifecycle.kuml.kts \
--animated --trace order-lifecycle.trace.json \
--format webp
kuml render order-lifecycle.kuml.kts \
--animated --trace order-lifecycle.trace.json \
--format mp4
| Format | Requirements |
|---|---|
|
None — pure-JVM frame assembly. |
|
|
|
|
MP4/H.264 has no standard alpha-channel support. --format=mp4 always renders against
an opaque background. Use apng or webp when a transparent background is required.
|
Frame count and duration are capped (FrameBudget) to prevent runaway output size; see the
CLI --speed option above for compressing a long trace into a shorter animation instead.
Static fallback
When --animated is omitted, or when the trace produces no animations, the renderer
falls back to a static SVG that is byte-identical to the output of kuml render without
--animated. This guarantees that switching animation on/off does not change the diagram
layout.
You can also strip SMIL elements from an existing animated SVG:
import dev.kuml.io.smil.SmilEmitter
import dev.kuml.io.smil.StaticSnapshotMode
val staticSvg = SmilEmitter.inject(animatedSvg, timeline = null, mode = StaticSnapshotMode.STRIPPED)
STRIPPED removes every <animate*> and <set > element and suppresses injection of
new ones — safe for PNG rendering pipelines.
Embedding the renderers
import dev.kuml.io.smil.BpmnSmilRenderer
import dev.kuml.io.smil.StmSmilRenderer
// BPMN animated SVG
val bpmnSvg = BpmnSmilRenderer().render(bpmnDiagram, traceFile, speedFactor = 1.0)
// UML / SysML 2 State Machine animated SVG
val stmSvg = StmSmilRenderer().render(stmDiagram, traceFile, speedFactor = 1.0)
Both renderers are in kuml-io/kuml-render-smil (dev.kuml:kuml-render-smil).
Browser compatibility
Animated kUML SVGs play back in all evergreen browsers (Chrome 88+, Firefox 63+,
Safari 13.1+). The <animateMotion> and <animate> elements used are part of the
SVG/SMIL subset that all major browsers support. Internet Explorer is not supported.
Full cross-browser support (Chrome and Safari in addition to Firefox) requires
v0.20.1 or later. Earlier releases used the SVG-2 bare href attribute on SMIL
elements; browser SMIL implementations are based on SVG 1.1 and require xlink:href
together with the xmlns:xlink namespace declaration on the <svg> root. Firefox
played animations correctly in all versions; Chrome and Safari silently ignored the
SMIL elements until the fix in v0.20.1 (SmilEmitter now emits xlink:href and
injects xmlns:xlink into the root tag automatically).
|
See also
-
State-Machine Simulation — how to produce traces
-
BPMN 2.0 DSL — authoring BPMN process models