Skip to content
datalayerPublic

About

☰ πŸƒ Datalayer Decks.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Datalayer

☰ πŸƒ Datalayer Decks

Slide decks, described as data β€” and the Reactor plugin that puts them in any Reactor shell.

spec (.ts, YAML-shaped)
   ↓  validation
template            branding, palette, type scale, layout overrides
   ↓
slide library       reusable semantic slide types
   ↓
@revealjs/react β†’ Reveal.js

A spec says type: metrics; how a metrics slide looks is the template's business. That is what lets one deck be an application deck, a conference talk and a dark projection deck by changing one word.

Installation

pip install datalayer_decks
datalayer decks serve          # http://127.0.0.1:8797, opens the browser
datalayer decks serve my-deck.yaml  # load YAML and open this deck directly
datalayer decks list

Installing the package adds a decks group to the Datalayer CLI β€” serve, list, show, delete β€” through the reactor's datalayer.cli entry-point group; datalayer-decks is the same group on its own. serve runs the decks API (/decks, JSON specs on disk) and the interface built from app/ from one origin. The interface is a Reactor shell: the decks plugin in the sidebar and main slots, the plugins manager, the command palette, and β€” at the header's right edge β€” the appearance menu of @datalayer/primer-addons, the color mode and theme chooser the Datalayer header wears. Set DATALAYER_DECKS_DIR (or --decks-dir) to choose where decks are stored (~/.datalayer/decks otherwise).

A YAML file passed to serve is loaded into a temporary store and opened at its deck URL, so trying a file does not alter the user's normal deck catalog. Pass --decks-dir as well when the imported copy should persist. A diagram is ordinary spec content, either as a full slide or inside a column:

- type: mermaid
  title: From specification to screen
  diagram: |
    flowchart LR
      YAML[Deck YAML] --> Validate
      Validate --> Reveal[Reveal.js]

Installed beside any other Reactor host, the same wheel publishes itself as an extension: the routes join that host, and the Decks plugin β€” built by extension/ as a Module Federation container into share/datalayer/reactor/extensions/decks β€” is loaded into that host's shell through federation, no import needed. See python-packaged extensions.

Usage

import { registerDecks, DeckView, DecksHostProvider } from '@datalayer/decks';
import { DecksPlugin } from '@datalayer/decks/plugin';
  • @datalayer/decks β€” the engine: types, validateDeck, the slide library, the templates (datalayer, datalayer-brand, datalayer-ink), DeckRenderer, DeckView, DeckPrintView, DeckAccess, and two registries the host fills β€” the deck catalog (registerDecks) and the components a spec may name (registerDeckComponents).
  • @datalayer/decks/plugin β€” DecksPlugin: a list in the sidebar slot, the open deck in main, a "Decks" entry in the shell's view selector, and commands with keystrokes.
Command Keystroke Does
decks.list Mod+Shift+D close the open deck, show the list
decks.new Mod+Alt+N the "new deck" dialog
decks.open β€” open a deck by id ({ id, slide? })
decks.rename F2 rename the open deck (or { id }): title, address, family
decks.delete β€” delete the open deck (or { id }), after asking
decks.goToSlide β€” move the open deck to a slide ({ slide })
decks.nextSlide / decks.previousSlide Alt+β†’ / Alt+← move through the open deck
decks.present Mod+Shift+F the open deck, fullscreen
decks.print Mod+Shift+P the print view, for Save as PDF

What the engine needs from the application around it β€” the theme, a footer logo, whether the reader is signed in β€” arrives through DecksHostProvider, with defaults that make a bare mount work.

Notes, Play and Video

Every slide may carry notes. Above a deck, Notes shows them to the presenter (never in the PDF). When the host gives a voice (DecksHost.useNarrator, a DeckNarrator), two more buttons follow Download PDF:

  • Play reads the notes aloud, slide after slide, as captions at the bottom of the slide; a slide without notes stays four seconds.
  • Video makes the same into a video file, in the browser: each slide drawn at 1920Γ—1080 (fragments shown, fonts, pictures and Mermaid diagrams waited for), each sentence voiced by the narrator's synthesize(sentence) β€” the whole audio of one sentence, in a format AudioContext.decodeAudioData reads β€” and the deck recorded with the sentence being said as a caption, with MediaRecorder: MP4 where the browser records it, WebM otherwise. It records in real time, with its progress, Sound on/off and Cancel above the deck, and keeps going in a background tab. You see and hear it as it records β€” the deck on screen follows the slide being recorded, with its caption, as Play does, and goes back where you were at the end; Sound off silences the speakers only, the video keeps its sound. Then it offers the video and a WebVTT captions file with the same sentences and timings, named after the deck.

A host that keeps the video passes DeckView a videoPublisher (DeckVideoPublisher: a label, publish(made, spec), and what to say once published) β€” or gives it once, for every deck under it, as DecksHost.videoPublisher (how a host keeps the video of a deck the plugin draws; DeckView's own prop wins). Video then reads as the label, and the video β€” with its captions and poster, the first slide as a 1920Γ—1080 PNG β€” is handed to publish as soon as it is made, with spec, the deck as it was when Video was pressed, so the host can tell later whether the video is still the deck's; a refusal shows its reason with Upload again.

The landing does this twice. On a deck's page in its space, the video is saved with the deck (Spacer, PUT /api/spacer/v1/decks/{id}/video, in the private bucket): the next time the page opens it plays above the slides with Download, without being made again, and Video reads Make again β€” the page says so when the deck was edited after it was made. Publishing that deck to the Library offers Publish as a video, which copies the saved video into the Library's public one. On a published deck's Library page, its owner's Make the video uploads straight to the Library.

A narrator without synthesize gives no Video button. A narrator that cannot speak for this reader (unavailable, with needsSignIn when signing in is the way out) has both buttons say why rather than play or record.

Agents

Everything an agent may do with decks is declared by this plugin, as one AgentTools bundle (src/plugin/agentTools.json): the data β€” decks_list_decks, decks_get_deck, decks_create_deck, decks_update_deck, the per-slide edits, decks_delete_deck β€” and the screen β€” decks_open, decks_go_to_slide, decks_next_slide, decks_previous_slide, decks_present, decks_print, decks_list. Each is a command the plugin registers (DECKS_DATA_COMMANDS, DECKS_COMMANDS), run on the page against the catalog and the store β€” saved to this server when the plugin was given one β€” and answering with what the model needs next. No agentspec names a deck tool; example-decks declares tools: [] and gets them all from the plugin it is mounted beside.

The Python half serves the same file from GET /plugins/agent-tools, and registers the data half of the suite under the same ids (datalayer_decks/commands.py, through provide_slash_commands) β€” so on a host with no browser the commands the bundle names are commands the reactor actually has, reachable from reactor commands list and reactor commands run decks.getDeck '{"id": "talks/hello"}' as much as from an agent. The seven that move a deck on screen stay with the browser plugin: a store has no screen.

In the datalayer decks interface itself, --reactor-plugins ai-agents puts the Decks agent (example-decks) beside the decks: a floating chat on a temporary inference key, with the bundle above as its tools, read from the reactor rather than declared β€” see plugins/ai-agents. example-decks and worker-pitcher (the landing's deck editor agent) name the same frontend toolset, decks, in agentspecs.

In a Loop (@datalayer/agent-runtimes), @datalayer/loop-plugin-decks mounts this plugin beside the chat β€” the list in the sidebar, a Deck editor view, a menu on the composer β€” and the chat hands the agent the bundle's commands as tools, so an agent writes and drives a deck with no server behind it. The DecksAgent example shows it.

Development

make install          # pip install -e ".[test]"
make build-lib        # tsc β†’ lib/
make build-app        # the interface β†’ share/datalayer/reactor/apps/decks
make build-extension  # the container β†’ share/datalayer/reactor/extensions/decks
make wheel            # both, then the wheel (hatch_build.py builds what is missing)
make test
make dev-app          # Rsbuild on :5190, against `datalayer decks serve` on :8797
make example          # serve examples/welcome/welcome.yaml directly

The container build needs @module-federation/rsbuild-plugin (a devDependency): npm install once in this package.

The deck definitions of a product stay with that product: the Datalayer landing keeps its specs, its registry entries and its design-system illustrations, and mounts this package around them.

About

☰ πŸƒ Datalayer Decks.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Contributors

Languages