Play .df in Runtime

Overview

Runtime playback is split into two layers:

  • @designful/df-runtime-core for deterministic playback and state machine evaluation
  • @designful/df-runtime-core/runtime for tree-shakeable runtime-only embedding
  • @designful/df-player-web for browser controls and rendering (konva by default, canvas2d fallback)

Script-related note:

  • Editor script authoring APIs (createScript, runScriptHook, script diagnostics) are documented under /help/animation/script-*.
  • Exported .df manifests preserve validated script metadata at manifest.runtime.animationScripts for parity and tooling inspection.
  • .df runtime currently focuses on timeline/state-machine playback; script authoring hooks are not a runtime public API in this page.

Low-level Runtime

import { createRuntimeInstance, loadDf } from '@designful/df-runtime-core'

const document = await loadDf('/assets/sample.df')
const runtime = createRuntimeInstance(document, { autoplay: false, loop: true })

runtime.play()
runtime.setInput('machine-main', 'hover', true)
runtime.fireTrigger('machine-main', 'click')

setInput and fireTrigger evaluate transition eligibility immediately, so state-machine transitions can start even while playback is paused. A later click trigger can also drive a return transition (for example toggling active style back to idle/hover on second click) when your state machine defines it. When .df contains embedded buffers, loadDf hydrates image assets referenced by bufferId into runtime data URLs automatically. This allows loading embedded-image .df binaries in offline/sandboxed environments without external image fetch.

Web Player

import { DfPlayer } from '@designful/df-player-web'

const player = DfPlayer.mount(container, { autoplay: false, fit: 'contain' })
await player.load('/assets/sample.df')

player.play()
player.seek(500)
container.addEventListener('pointerenter', () => {
  player.setInput('machine-main', 'hover', true)
})
container.addEventListener('pointerleave', () => {
  player.setInput('machine-main', 'hover', false)
})
container.addEventListener('click', () => {
  player.fireTrigger('machine-main', 'click')
})

Script Tag (UMD)

For no-build-tool integration, use the vanilla UMD bundle from @designful/df-player-web:

<div id="player" style="width: 480px; height: 320px;"></div>
<script src="/path/to/vanilla.umd.js"></script>
<script>
  const player = window.DesignfulDfPlayer.DfPlayer.mount(
    document.getElementById('player'),
    { autoplay: false, fit: 'contain' },
  )
  player.load('/assets/sample.df')
</script>

You can also open the standalone no-build demo at /demos/df-player-vanilla.html.

Lifecycle option layering:

  • mount(container, createOptions) configures renderer/layout/interaction baseline.
  • player.load(src, loadOptions) applies source-scoped playback defaults.
  • player.reset(resetOptions) applies seek/playback reset behavior without remounting.

Interaction policy precedence:

  1. Runtime updates via player.setInteractionPolicy(...)
  2. mount(..., { interaction })
  3. Asset defaults from manifest.runtime.interactionDefaults
  4. Built-in fallback defaults

Enable render hooks and debug HUD:

const player = DfPlayer.mount(container, {
  autoplay: false,
  debugOverlay: true,
  renderHooks: {
    beforeRender: ({ state }) => console.log('before', state.currentTimeMs),
    afterRender: ({ state }) => console.log('after', state.currentTimeMs),
  },
})

Select a specific timeline explicitly:

const player = DfPlayer.mount(container, {
  timelineId: 'timeline-main',
  autoplay: false,
  fit: 'contain',
})

Force legacy Canvas2D mode:

const player = DfPlayer.mount(container, {
  renderer: 'canvas2d',
  autoplay: false,
  fit: 'contain',
})

Update layout through immutable copyWith-style API:

player.setLayout({
  fit: 'cover',
  alignX: 'end',
  alignY: 'center',
})

Runtime Events

You can subscribe to:

  • load
  • ready
  • assetProgress
  • stateChange
  • diagnostics
  • loop
  • complete
  • error

loop and complete are emitted for both standalone timelines and state-machine-driven playback (derived from the active state timeline duration). assetProgress emits error for image assets that cannot produce a loadable source (for example missing src and unresolved bufferId) so callers can surface fallback UI.

Rendering Visibility Behavior

When the document is hidden (or player container is offscreen), runtime rendering is paused automatically while playback state is preserved. Rendering resumes when visibility returns.

Deprecation Aliases

Temporary migration aliases (with one-time warning):

  • dispose() -> destroy()
  • startRenderLoop() -> startRendering()
  • stopRenderLoop() -> stopRendering()

Migration notes template: /help/animation/df-runtime-migration-notes-template

Docs Demo Quick Capture

In /docs/api/managers/df-runtime, the runtime demo toolbar includes:

  • Export .df to save current loaded runtime source
  • Export PNG and Export WebP for current canvas frame snapshots
  • Export WebM for a short recorded preview segment
  • runtime diagnostics summary + itemized table (level / code / message / path)
    • includes unresolved image asset diagnostics (IMAGE_ASSET_NOT_FOUND, IMAGE_ASSET_TYPE_MISMATCH)

Current Runtime Scope (V1)

Supported today:

  • timeline sampling and easing in runtime core
  • state machine inputs/transitions in runtime core
  • Konva renderer reusing editor NodeFactory for higher playback parity
  • Canvas2D fallback renderer for frame, text, image, pen-path, and shape variants (rect, circle, ellipse, line, arrow, polygon, star, path, arc)
  • hierarchy transform inheritance (group as container node)
  • frame clipping (frame.clipContent) in Canvas2D fallback
  • blend mode mapping (blendMode -> globalCompositeOperation) in Canvas2D fallback
  • image asset preload + crop support in Canvas2D fallback
  • font preload via browser document.fonts (both renderers); URL font assets use FontFace when available
  • image loading/error placeholder rendering in Canvas2D fallback (missing assets do not crash playback)
  • font fallback chain in Canvas2D fallback (fontFamily -> sans-serif) with warning logs on load failures

Current limits:

  • advanced visual effects still have lower parity in Canvas2D adapter (use Konva renderer path for full parity)
  • runtime does not re-run editor auto-layout; playback uses exported transforms/sizes

Canvas2D Compatibility Diagnostics

When renderer: 'canvas2d', player runs load-time feature checks and appends warnings to diagnostics when capability gaps are detected.

FeatureDiagnostic codeRuntime impact
Path2D unavailable for path shapesCANVAS2D_PATH2D_UNSUPPORTEDPath rendering can be incomplete
advanced text metrics unavailable (actualBoundingBox*)CANVAS2D_TEXT_METRICS_LIMITEDText wrapping/alignment can differ by browser
blend mode composite operation unsupportedCANVAS2D_BLEND_MODE_UNSUPPORTEDBlend mode falls back to source-over

Image URL CORS Requirements

For URL-backed image assets (asset.src):

  • player loads images with crossOrigin='anonymous'
  • image host must allow your app origin with CORS headers (or * when credentials are not required)
  • if CORS blocks fetch/decode, assetProgress reports status='error' and runtime draws placeholders

For portable or offline playback, prefer embedded image assets (bufferId) from exporter.

Default timeline resolution:

  • with timelineId: use that timeline
  • without timelineId + state machines: use state-machine timelines
  • without timelineId + no state machines: first timeline with tracks (fallback first timeline)

Debugging

  • Use player.getState() to inspect current timeline time and active machine state.
  • Enable debugOverlay: true to display time/state/fit data directly on canvas.
  • Use runtime.getDiagnostics() to inspect format/runtime warnings and errors.
  • Use @designful/df-validator before load to fail fast on invalid binaries/documents.
  • CI includes runtime perf smoke checks (medium .df load budget, playback loop budget, tick+render average frame budget, simulated 5-minute heap growth stability).
  • CI also includes runtime package boundary checks (no runtime-package dependency cycles, no dependency on editor UI package).