Generate web slides from Markdoc

CLAUDE.md#

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Development Commands#

  • Start development server: deno task dev (uses scripts/dev.ts with runtime bundling and file watching)
  • Core development server: deno task dev:core (direct main.ts dev command)
  • Runtime development: deno task dev:runtime (bundles runtime to dist/)
  • Build static presentation: deno task build <markdoc-file> or deno run --allow-env --allow-read --allow-write main.ts build <markdoc-file> --output <directory>

Architecture Overview#

morkdeck is a slideshow generator that converts Markdoc files into web-based presentations. The architecture follows a modular pipeline with clear separation of concerns:

Directory Structure#

morkdeck/
├── cli/              # CLI command definitions
│   ├── dev.ts        # Dev command interface
│   └── build.ts      # Build command interface
├── core/             # Core rendering logic
│   ├── markdoc-config.ts    # Markdoc configuration
│   ├── nodes/        # Custom Markdoc nodes
│   │   └── fence.ts  # Code fence with Shiki/Mermaid
│   ├── renderer.ts   # Main rendering pipeline
│   └── types.ts      # TypeScript type definitions
├── runtime/          # Client-side runtime components
│   ├── components/   # Lit-based web components
│   │   ├── presentation.ts  # Presentation component
│   │   └── slide.ts  # Slide component
│   └── morkdeck.ts   # Runtime entry point
├── scripts/          # Development scripts
│   └── dev.ts        # Enhanced dev command with esbuild
├── server/           # Development server implementation
│   └── dev.ts        # Live-reload server logic
├── templates/        # Eta templates
│   ├── presentation.eta     # Main template
│   ├── components/   # Component templates
│   │   ├── presentation.eta # Inline Lit presentation component
│   │   └── slide.eta # Inline Lit slide component
│   └── partials/     # Template partials
│       ├── live-reload.eta  # Live-reload scripts
│       ├── mermaid.eta      # Mermaid initialization
│       └── slide-styles.eta # CSS styles
├── dist/             # Built runtime assets
└── main.ts          # Entry point

Core Components#

  1. CLI Layer (cli/): Command definitions using Cliffy framework

    • cli/dev.ts: Dev command that delegates to server implementation
    • cli/build.ts: Build command for static HTML generation
  2. Runtime Layer (runtime/): Client-side web components using Lit

    • runtime/components/presentation.ts: Presentation container with scroll-snap and URL sync
    • runtime/components/slide.ts: Individual slide component
    • runtime/morkdeck.ts: Custom element registration entry point
    • Built to dist/morkdeck.js via esbuild
  3. Scripts Layer (scripts/): Enhanced development tooling

    • scripts/dev.ts: Orchestrates both runtime bundling and core server with file watching
    • Watches runtime files and rebuilds with esbuild
    • Watches core files and restarts development server
  4. Server Layer (server/): Development server functionality

    • server/dev.ts: Live-reload server, file watching, WebSocket handling
    • Serves presentations at port 8000
    • Uses consolidated template system
  5. Core Rendering (core/): Markdoc processing and rendering

    • core/renderer.ts: Unified rendering pipeline with renderPresentationHtml()
    • core/markdoc-config.ts: Markdoc configuration with includes tracking
    • core/nodes/fence.ts: Code fence node with Shiki syntax highlighting and Mermaid support
    • core/types.ts: Type definitions for render options and includes

Key Dependencies#

  • @cliffy/command: CLI framework
  • @eta-dev/eta: Template engine for HTML generation
  • @markdoc/markdoc: Markdoc parsing and rendering
  • shiki: Syntax highlighting for code blocks
  • hast-util-is-element: HAST tree utilities for Shiki integration
  • lit: Web component library for runtime components
  • esbuild: Runtime bundling and TypeScript compilation
  • @deno/esbuild-plugin: Deno module resolution for esbuild

Template System#

Hybrid Template Architecture:

  • templates/presentation.eta: Main template for both dev and static builds
  • templates/components/: Inline Lit component templates
    • presentation.eta: Inline Lit Presentation component with IntersectionObserver
    • slide.eta: Inline Lit Slide component
  • templates/partials/: Modular template components
    • importmap.eta: Import map for Lit CDN dependencies
    • live-reload.eta: WebSocket live-reload functionality (dev only)
    • mermaid.eta: Mermaid diagram initialization scripts
    • slide-styles.eta: CSS styling for presentations

Template Features:

  • Includes System: Dynamic script/style injection based on content needs
  • Mode Detection: Automatic dev vs static build differentiation
  • Partial Composition: Modular template components for maintainability

Presentation Structure#

  • Each Markdoc file represents a complete presentation
  • Slides are separated by --- (horizontal rules)
  • The rendering process wraps each slide section in semantic HTML with custom web components:
    • morkdeck-presentation → Lit-based presentation container
    • morkdeck-slide → Lit-based individual slide wrapper
  • Presentation component handles scroll-snap navigation and URL synchronization
  • IntersectionObserver tracks visible slides and updates browser URL hash

Code Highlighting Features#

  • Shiki Integration: Rose Pine theme syntax highlighting for code blocks
  • Mermaid Support: Automatic detection and script injection for Mermaid diagrams
  • Language Detection: Automatic language detection from fence attributes
  • HAST Processing: Converts Shiki HAST output to Markdoc render nodes

Build System#

Development Mode (deno task dev):

  • Enhanced development workflow via scripts/dev.ts
  • Runtime bundling with esbuild watching runtime/ directory
  • Core server restart when core/, server/, or cli/ files change
  • Live-reload server at port 8000
  • WebSocket-based browser refresh
  • No cache headers for development

Core Development Mode (deno task dev:core):

  • Direct main.ts dev command execution
  • Basic file watching without runtime bundling

Runtime Development (deno task dev:runtime):

  • Standalone runtime bundling to dist/morkdeck.js

Static Build (deno task build):

  • Single HTML file output with embedded runtime
  • No live-reload dependencies
  • Optimized for deployment
  • Custom output directory support

Styling Approach#

The presentation uses a dark theme with centered layout:

  • Full viewport slides with scroll-snap navigation via Lit component CSS
  • Container queries for responsive typography
  • Recursive font family with variable font features and monospace code support
  • Rose Pine color scheme (#191724 background, #e0def4 headings, #908caa text)
  • Shadow DOM styling in Lit components with :host selectors

Extending the System#

Adding Custom Markdoc Nodes:

  1. Create a new file in core/nodes/
  2. Export a function that returns a Markdoc node configuration
  3. Import and add to the nodes object in core/markdoc-config.ts

Adding Runtime Components:

  1. Create new Lit components in runtime/components/
  2. Register custom elements in runtime/morkdeck.ts
  3. Add corresponding template components in templates/components/ if needed

Adding Template Partials:

  1. Create new .eta files in templates/partials/
  2. Use includes system to conditionally load based on content needs
  3. Update core/markdoc-config.ts to track new includes

Development Workflow#

Primary Development Command: Use deno task dev for the full development experience with:

  • Automatic runtime bundling and rebuilding
  • Core server restart on backend changes
  • Live browser reload
  • Port 8000 presentation serving