Skip to content

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 localStorage persistence (versioned, fingerprinted key)
  • mounted-slides policy (all | adjacent | current)
  • focus ring, prefers-reduced-motion, print @page injection
  • slidechange CustomEvent (typed, versioned payload)
  • postMessage bridge for studio embedding

The engine is frozen behind engineCompat:1 and eventVersion:1. Any breaking change requires bumping those markers.

deck-stage:v2:<persist-key>:slide

persist-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:

  1. Authoring AST — the shape the YAML must conform to (Zod).
  2. Deck IR — versioned, normalized, render-agnostic. Stable for diffing, caching, and future non-React renderers.
  3. Render plan — runtime-shaped tree consumed by IRRenderer.

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.

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”
TargetModule loadingCSS code splittingUse case
screenlazyondev + production app
printeageroffPDF / 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.

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 from decks/<slug>/deck.yaml through 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.

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.