Skip to content

Configuration ​

There are three places to configure dek: the project's dek.toml, the frontmatter of each deck's script.md, and the optional voice/ files inside a deck.

Directory layout ​

my-talks/
├── dek.toml
├── .gitignore
├── .rumdl.toml
├── theme.css
├── tsconfig.json
├── AGENTS.md
├── assets/
├── refs/                          # gitignored; fetched again from [refs]
│   └── owner/repo/deck/
├── decks/
│   └── 2026-04-vite/
│       ├── script.md
│       ├── theme.css
│       ├── voice/                 # optional
│       │   ├── voice.toml
│       │   ├── dict.toml
│       │   └── pin/
│       ├── slides/
│       ├── assets/
│       ├── dist/
│       │   ├── 2026-04-vite.html
│       │   ├── 2026-04-vite.png
│       │   ├── 2026-04-vite.pdf
│       │   ├── 2026-04-vite.mp4
│       │   ├── 2026-04-vite.vtt
│       │   ├── 2026-04-vite.chapters.txt
│       │   └── 2026-04-vite.credits.txt
│       └── .cache/
│           ├── voice/
│           ├── video/
│           └── shots/
└── .dek/
    ├── schema.json
    ├── slide.d.ts
    └── server.json                # while the dev server runs

The boundary between project and deck is explained in Projects and Decks.

dek.toml ​

toml
# dek project
url = "https://example.com/talks/"
max_classes = 40
cjk_per_minute = 300
latin_per_minute = 130

[voice]
engine = "voicevox"
speaker = "ずんだもん/ノーマル"
speed = 1.0

[refs]
"hajimism/dek/why-dek" = "89fbd5a0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6"
KeyDefaultPurpose
urlnoneThe absolute http(s) URL dist/ is served from. With it, dekc build writes og:url and a first-slide og:image; --url overrides it. See On the web
max_classesnoneSeed for a new deck's max_classes; see Frontmatter
cjk_per_minutenoneSeed for a new deck's cjk_per_minute
latin_per_minutenoneSeed for a new deck's latin_per_minute
voice.engine"voicevox"Engine name (voicevox, aivis, coeiroink, sharevox), a name and a local port (voicevox:50021), or a base URL
voice.speakerrequired when [voice] is presentSpeaker, as name/style
voice.speed1.0Speaking speed
refsnoneEach ref (owner/repo/deck) and the 40-character commit it is pinned to. dekc ref writes it; see Refs

dek ignores keys it does not know, and lint names each one as DEK008, with the key it most likely meant.

max_classes, cjk_per_minute, latin_per_minute, and [voice] are seeds: dekc new copies the first three into the new deck's frontmatter and [voice] into voice/voice.toml, and from then on the deck reads only its own copy. Changing them in dek.toml leaves the decks already made as they were. A deck that leaves out a key dek.toml sets to something other than the default is a DEK008 warning whose hint names the line to add.

Frontmatter ​

The schema is defined with Zod and written to .dek/schema.json on every sync. The $schema comment on the first line lets yaml-language-server validate as you type.

yaml
---
# yaml-language-server: $schema=../../.dek/schema.json
title: How I Built an HTML Slide Tool
description: What a build system for talks looks like, and why the script comes first.
event: Tokyo Frontend Meetup #42
date: 2026-04-18
duration: 20m
ratio: 16:9
lang: en
---
KeyRequiredValue
titleyesString. Used as the heading of the first skeleton slide when its ## heading is only an id
descriptionnoString. The description a shared link shows; without it, event and date stand in
eventnoString. Shown by dekc ls; not placed on any slide
datenoYYYY-MM-DD
durationno<n>m, such as 20m. The talk's budget
rationo16:9 (default, 1280 × 720) or 4:3 (1024 × 768)
langnoBCP 47 tag. Becomes <html lang> in the player, screenshots, and PDF. Omit it and dek reads the script: kana means ja, then Hangul ko, then Han zh, and anything else en
max_classesnoThe most classes theme.css may define (DEK013). Default 40
cjk_per_minutenoSpeaking rate for CJK text, in characters a minute. Default 300
latin_per_minutenoSpeaking rate for other text, in words a minute. Default 130

Any other key is ignored, and lint names it as DEK008.

Section and beat ids match [a-z0-9-]+ and contain at least one letter. Digits-only ids would collide with numeric data-step values.

voice/voice.toml ​

toml
engine  = "voicevox"
speaker = "ずんだもん/ノーマル"
speed   = 1
pause   = { sentence = 350, beat = 700 }
KeyPurpose
engineEngine name or base URL. Default voicevox. DEK_VOICE_URL overrides it
speakername/style. dekc voice speakers lists what the engine offers
speedSpeaking speed. Default 1
pause.sentenceSilence between sentences, in milliseconds. Default 350
pause.beatSilence at a beat boundary, in milliseconds. Default 700
leadHow far each screen change leads its first word, in milliseconds. Default 300
beats."<key>".leadlead into one slide's arrival (slug, slug/0) or into one beat (slug/beat-id, slug/2)
beats."<key>".pauseSilence after that beat, or after a slide's last beat, replacing pause.beat

voice/dict.toml ​

Readings for words the engine would otherwise mispronounce. Keys are matched as whole ASCII words, longest first.

toml
[dek]
kana = "デック"

["script.md"]
kana = "スクリプトエムディー"

dekc voice dict add <word> <kana> appends an entry. A word not in the dictionary is DEK040.

Theme tokens ​

Custom properties every theme publishes on .slide. Never on :root.

TokenRole
--fg --bg --accent --mutedColor
--font-title --font-bodyType
--size-title --size-body --size-captionSize
--gap --padSpace
--radiusCorners
--step-transitionMotion

Bundled layouts ​

Values of data-layout in the bundled theme.

ValueUse
titleA title with no beats
defaultThe default for slides with beats. Top-aligned, so the heading stays put as elements appear
two-colTwo columns
full-bleedEdge to edge, no padding
quoteA quotation

Skeletons use title for a section without beats and default otherwise.

Released under the MIT License.