Architecture
Engine kernel — @alexbayerl/djed-deck-stage
Section titled “Engine kernel — @alexbayerl/djed-deck-stage”The engine is a single web component, <deck-stage>. It owns:
- keyboard navigation, tap zones, swipe gestures
- per-deck
localStoragepersistence (versioned, fingerprinted key) - mounted-slides policy (
all | adjacent | current) - focus ring,
prefers-reduced-motion, print@pageinjection slidechangeCustomEvent(typed, versioned payload)postMessagebridge for studio embedding
The engine is frozen behind engineCompat:1 and eventVersion:1.
Any breaking change requires bumping those markers.
Persistence keys
Section titled “Persistence keys”deck-stage:v2:<persist-key>:slidepersist-key is supplied by the host page and should encode either the
deck slug or a content fingerprint, so persistence survives route
moves but resets when the deck content changes.
Primitives + themes — @alexbayerl/djed-deck-kit
Section titled “Primitives + themes — @alexbayerl/djed-deck-kit”The kit exposes layout, typography, surface, brand, and viz primitives.
Everything is driven by CSS custom properties scoped per theme via
[data-deck-theme="…"]. Tailwind v4 aliases those raw vars through a
single @theme static inline block in deck-kit/styles.css.
:root, [data-deck-theme="djed"] { --deck-bg: #0b0f14; /* … */ }[data-deck-theme="atlas"] { --deck-bg: #0a0a0a; /* … */ }[data-deck-theme="osiris"] { --deck-bg: #08111a; /* … */ }
@theme static inline { --color-deck-bg: var(--deck-bg); /* … the full token surface, always emitted */}The kit also ships <DeckStage/> — a thin React adapter that wraps the
custom element with a typed JSX intrinsic, ref forwarding, an SSR
guard, and a single onSlideChange event hook.
Schema + IR — @alexbayerl/djed-deck-schema
Section titled “Schema + IR — @alexbayerl/djed-deck-schema”The schema is structured as three tiers:
- Authoring AST — the shape the YAML must conform to (Zod).
- Deck IR — versioned, normalized, render-agnostic. Stable for diffing, caching, and future non-React renderers.
- Render plan — runtime-shaped tree consumed by
IRRenderer.
JSON Schema export
Section titled “JSON Schema export”emitDeckJsonSchema() emits the authoring AST as Draft 2020-12 JSON
Schema with stable URN ids, $ref-based reuse (reused: "ref"), and
no transforms. The build writes the same object to
dist/deck.schema.json in the published package; Vitest golden-tests
dist/deck.schema.json against the in-memory emit so the on-disk
artifact cannot drift. This file is the contract for editor completion
and agent grounding.
CI (GitHub Actions)
Section titled “CI (GitHub Actions)”The root Test workflow path-filters include decks/**,
services/decks/**, tools/deck-cli/**, and packages/** so
deck-only changes still run. A deck-engine job builds
@alexbayerl/djed-deck-schema + deck-kit + deck-stage, runs
Vitest for schema and kit, then Playwright for the engine. Use
pnpm run test:deck locally as a shortcut.
Per-target build contract — @alexbayerl/djed-deck-cli
Section titled “Per-target build contract — @alexbayerl/djed-deck-cli”| Target | Module loading | CSS code splitting | Use case |
|---|---|---|---|
screen | lazy | on | dev + production app |
print | eager | off | PDF / browser print |
Print mode also waits for document.fonts.ready before triggering
output — empirically the most common cause of broken PDFs in earlier
deck implementations.
Reference application — services/decks
Section titled “Reference application — services/decks”services/decks is a Vite multi-page app that consumes decks from
the top-level decks/ directory rather than owning content. Routes:
/— landing hub (catalog-driven cards with live first-slide previews and an Embed dialog)/decks.json— build-time catalog artifact (see Embedding doc)/playground/index.html— primitive gallery/playground/yaml/index.html— live YAML editor (compile + render in browser)/d/<slug>/index.html— screen runtime/d/<slug>/print.html— print runtime, optional?autoprint=1/d/<slug>/yaml.html— preview of the deck compiled fromdecks/<slug>/deck.yamlthrough the IRRenderer
This separation keeps content portable: the same decks/<slug> can be
rendered by the reference app, embedded in studios, or built straight
to PDF by the CLI.
Catalog flow (vite-plugin-decks-manifest)
Section titled “Catalog flow (vite-plugin-decks-manifest)”The hub does not maintain a hand-written deck list. A small Vite
plugin under services/decks/plugins/decksManifest.ts walks
decks/*/deck.yaml at build start, calls compileYaml(), filters by
meta.hub: true, and emits a single dist/decks.json asset (also
served at /decks.json in dev via middleware). The same plugin runs
transformIndexHtml on every index|print|yaml.html to inject
description + OG + canonical tags from the catalog entry, so each
route is shareable as-is.
See the Embedding page for the catalog shape and how to consume it from third-party hosts.