@entropicwarrior/sdoc 0.2.18 → 0.2.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/docs/reference/sdoc-authoring.sdoc +1 -1
- package/docs/reference/slide-authoring.sdoc +441 -20
- package/package.json +4 -1
- package/src/slide-geometry.js +470 -0
- package/src/slide-layouts.js +514 -0
- package/src/slide-pdf.js +9 -3
- package/src/slide-pptx.js +599 -0
- package/src/slide-renderer.js +93 -57
- package/src/theme.js +141 -0
- package/src/zip.js +102 -0
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ Markdown has no formal structure — section boundaries are ambiguous, extractio
|
|
|
19
19
|
|
|
20
20
|
**A zero-dependency JavaScript parser** — `src/sdoc.js` parses SDOC into a format-neutral AST. No runtime dependencies, works anywhere Node runs. Parsing and rendering are cleanly separated — build your own renderers on top.
|
|
21
21
|
|
|
22
|
-
**Slide deck generation** — turn any SDOC file into
|
|
22
|
+
**Slide deck generation** — turn any SDOC file into a slide deck with themes, structured layouts (columns, stats, pipeline, matrix, rows, bars, split, stack), speaker notes, mermaid diagrams, and export to PDF or PowerPoint / Google Slides via headless Chrome.
|
|
23
23
|
|
|
24
24
|
**A document site builder** — serve a folder of SDOC files as a browsable site with sidebar navigation, search, and split-pane comparison.
|
|
25
25
|
|
|
@@ -53,6 +53,9 @@ Open any `.sdoc` file and click the preview icon in the editor title bar, or run
|
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
55
|
node tools/build-slides.js deck.sdoc -o slides.html
|
|
56
|
+
node tools/build-slides.js deck.sdoc --pdf # one page per slide
|
|
57
|
+
node tools/build-slides.js deck.sdoc --pptx # Drive imports it as Google Slides
|
|
58
|
+
node tools/build-slides.js deck.sdoc --check # report slides whose content overflows
|
|
56
59
|
```
|
|
57
60
|
|
|
58
61
|
Each top-level scope becomes a slide. Set `type: slides` in `@meta`. See `docs/reference/slide-authoring.sdoc` for the full authoring guide.
|
|
@@ -196,7 +199,7 @@ Tag any section with `@id` and cross-reference it anywhere with `@id` — render
|
|
|
196
199
|
|
|
197
200
|
### Slides
|
|
198
201
|
|
|
199
|
-
Turn any SDOC file into
|
|
202
|
+
Turn any SDOC file into a slide deck with themes, structured layouts, speaker notes, and export to PDF or PowerPoint / Google Slides.
|
|
200
203
|
|
|
201
204
|
### Scope Types
|
|
202
205
|
|
|
@@ -9,10 +9,15 @@
|
|
|
9
9
|
|
|
10
10
|
# About @about
|
|
11
11
|
{
|
|
12
|
-
How to create
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
How to create presentation slides from SDOC files, and how to get
|
|
13
|
+
them out as HTML, PDF or a Google Slides deck. Covers the deck
|
|
14
|
+
structure, the slide properties, the plain layouts (default, center,
|
|
15
|
+
two-column) and the structured ones (title, section, columns, stats,
|
|
16
|
+
pipeline, matrix, rows, bars, split, stack), speaker notes, the theme
|
|
17
|
+
system, and CLI usage. Read the Quick Reference for everyday
|
|
18
|
+
authoring, [Structured Layouts](#structured-layouts) when a slide
|
|
19
|
+
needs more than prose, and the Full Example for a complete deck
|
|
20
|
+
template.
|
|
16
21
|
}
|
|
17
22
|
|
|
18
23
|
# Quick Reference @quick-reference
|
|
@@ -70,10 +75,38 @@
|
|
|
70
75
|
node tools/build-slides.js deck.sdoc --pdf
|
|
71
76
|
```
|
|
72
77
|
|
|
73
|
-
This produces \`deck.pdf\` using headless Chrome
|
|
74
|
-
|
|
78
|
+
This produces \`deck.pdf\` using headless Chrome, one page per
|
|
79
|
+
slide, at the theme's page size. Requires Chrome or Chromium
|
|
75
80
|
installed on the system.
|
|
76
81
|
|
|
82
|
+
To export for Google Slides or PowerPoint:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
node tools/build-slides.js deck.sdoc --pptx
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
This produces \`deck.pptx\`. See [PowerPoint and Google Slides
|
|
89
|
+
Export](#pptx-export) for what it contains and how to import it.
|
|
90
|
+
|
|
91
|
+
To choose what happens when the window is not the slide's shape:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
node tools/build-slides.js deck.sdoc --fit contain
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
See [Aspect Ratio and Fit](#fit) for the three modes.
|
|
98
|
+
|
|
99
|
+
To check that nothing has overflowed its slide:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
node tools/build-slides.js deck.sdoc --check
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
This builds the HTML, measures every slide in a browser, and
|
|
106
|
+
reports any whose content has run past the margin the theme
|
|
107
|
+
reserved. \`--pptx\` runs the same check for free, because it has
|
|
108
|
+
already measured the deck.
|
|
109
|
+
|
|
77
110
|
To use a custom theme:
|
|
78
111
|
|
|
79
112
|
```
|
|
@@ -85,20 +118,48 @@
|
|
|
85
118
|
```
|
|
86
119
|
node tools/build-slides.js deck.sdoc --pdf --theme path/to/theme -o presentation.pdf
|
|
87
120
|
```
|
|
121
|
+
|
|
122
|
+
\`--pdf\` and \`--pptx\` can run in one invocation; \`-o\` then names
|
|
123
|
+
the PDF and the PPTX takes the input's name.
|
|
88
124
|
}
|
|
89
125
|
|
|
90
126
|
# Slide Properties @properties
|
|
91
127
|
{
|
|
92
|
-
|
|
93
|
-
|
|
128
|
+
A slide scope may open with a run of \`key: value\` lines. They set
|
|
129
|
+
the layout and the furniture around the content, and they must come
|
|
130
|
+
before any content — a recognised key further down is ordinary
|
|
131
|
+
text. Separate each with a blank line, as in \`@meta\`.
|
|
94
132
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
133
|
+
{[table]
|
|
134
|
+
Key | Effect
|
|
135
|
+
\`config:\` or \`layout:\` | The layout. See [Layouts](#layouts) and [Structured Layouts](#structured-layouts).
|
|
136
|
+
\`kicker:\` | The small label above the title. On a \`title\` slide it moves below the statement.
|
|
137
|
+
\`lede:\` | A standfirst line under the title.
|
|
138
|
+
\`footnote:\` | Small print pinned under the body: provenance, caveats, sources.
|
|
139
|
+
\`status:\` | A second line under the kicker on a title slide, for a distribution notice.
|
|
140
|
+
\`accent:\` | \`primary\`, \`secondary\`, \`tertiary\` or \`neutral\`. An accent names a role; the theme chooses the colour.
|
|
141
|
+
\`numbered:\` | \`columns\` and \`rows\`. \`true\` numbers the children 01, 02, 03.
|
|
142
|
+
\`variant:\` | \`columns\` and \`rows\`. A named treatment, such as \`panel\` or \`mono\`.
|
|
143
|
+
\`weights:\` | \`split\` only. The ratio between panes, as in \`48 52\`.
|
|
144
|
+
\`highlight:\` | \`matrix\` only. \`last\`, or text matching the row's first cell.
|
|
145
|
+
\`arrow:\` | \`pipeline\` only. The glyph drawn between steps. Defaults to an arrow.
|
|
146
|
+
\`rule:\` | \`stack\` only. \`true\` draws a hairline between blocks.
|
|
147
|
+
\`value:\` | On a \`rows\` or \`bars\` child: the right-hand figure.
|
|
148
|
+
\`fill:\` | On a \`bars\` child: the bar length as a percentage, overriding the automatic scale.
|
|
149
|
+
\`caption:\` | On a \`columns\` child: a line set under the column.
|
|
150
|
+
}
|
|
100
151
|
|
|
101
|
-
|
|
152
|
+
A key is only configuration where it means something. \`config:\`,
|
|
153
|
+
\`kicker:\`, \`lede:\`, \`footnote:\`, \`accent:\` and \`status:\` are
|
|
154
|
+
understood by every scope; the rest are understood only by the
|
|
155
|
+
layout named against them above. Anywhere else they are ordinary
|
|
156
|
+
text — a slide opening "Value: the customer keeps their data."
|
|
157
|
+
renders that sentence, it does not silently swallow it. A
|
|
158
|
+
paragraph spanning more than one source line is never
|
|
159
|
+
configuration.
|
|
160
|
+
|
|
161
|
+
No config line means the default layout: left-aligned,
|
|
162
|
+
top-to-bottom.
|
|
102
163
|
}
|
|
103
164
|
|
|
104
165
|
# Speaker Notes @notes
|
|
@@ -172,7 +233,12 @@
|
|
|
172
233
|
\`[text](url)\` | \`<a>\`
|
|
173
234
|
\`\` / \`\` | \`<img>\` (with optional width/alignment)
|
|
174
235
|
Nested scope | \`<section>\` within the slide
|
|
175
|
-
|
|
236
|
+
Child scope, structured layout | One cell: a column, a stat, a pipeline row, a bar, a pane
|
|
237
|
+
\`kicker:\` | \`<div class="kicker">\` above the title
|
|
238
|
+
\`lede:\` | \`<p class="lede">\` under the title
|
|
239
|
+
\`footnote:\` | \`<div class="footnote">\` under the body
|
|
240
|
+
\`accent: secondary\` | \`accent-secondary\` class on the slide or cell
|
|
241
|
+
\`@notes\` child | Hidden \`<aside class="notes">\`, exported as PowerPoint speaker notes
|
|
176
242
|
}
|
|
177
243
|
}
|
|
178
244
|
}
|
|
@@ -212,6 +278,14 @@
|
|
|
212
278
|
```
|
|
213
279
|
}
|
|
214
280
|
|
|
281
|
+
# Beyond These Three @more-layouts
|
|
282
|
+
{
|
|
283
|
+
\`title\`, \`section\`, \`columns\`, \`stats\`, \`pipeline\`, \`matrix\`,
|
|
284
|
+
\`rows\`, \`bars\`, \`split\` and \`stack\` consume the slide's child
|
|
285
|
+
scopes and arrange them. See
|
|
286
|
+
[Structured Layouts](#structured-layouts).
|
|
287
|
+
}
|
|
288
|
+
|
|
215
289
|
# Two-Column Layout @two-column-layout
|
|
216
290
|
{
|
|
217
291
|
Use \`config: two-column\`. Child scopes become columns.
|
|
@@ -239,6 +313,144 @@
|
|
|
239
313
|
}
|
|
240
314
|
}
|
|
241
315
|
|
|
316
|
+
# Structured Layouts @structured-layouts
|
|
317
|
+
{
|
|
318
|
+
The plain layouts arrange whatever content a slide holds. A structured
|
|
319
|
+
layout instead consumes the slide's *child scopes* and arranges them
|
|
320
|
+
into a known shape. Each child scope becomes one cell: its heading is
|
|
321
|
+
the cell's label and its content is the cell's body, with the exact
|
|
322
|
+
reading depending on the layout.
|
|
323
|
+
|
|
324
|
+
All of them are optional. A deck that uses none of them behaves exactly
|
|
325
|
+
as it did before they existed.
|
|
326
|
+
|
|
327
|
+
{[table]
|
|
328
|
+
Layout | Children are | Use for
|
|
329
|
+
\`title\` | — | The opening slide. The heading sets as display type and the kicker moves below it.
|
|
330
|
+
\`section\` | — | A divider carrying one statement.
|
|
331
|
+
\`columns\` | Columns, side by side | Parallel points, a set of figures, a row of cards, a people grid.
|
|
332
|
+
\`stats\` | A figure and its caption | Two to four numbers that carry the slide.
|
|
333
|
+
\`pipeline\` | Rows of chained steps | A signal path, a process, a comparison of two paths.
|
|
334
|
+
\`matrix\` | — (takes a table) | A competitive comparison, with per-column accents and one row picked out.
|
|
335
|
+
\`rows\` | Label, body, value rows | A layered model, a timeline, a ledger.
|
|
336
|
+
\`bars\` | Labelled quantities | An allocation of money, effort or time.
|
|
337
|
+
\`split\` | Two panes | Prose beside a figure, an argument beside its schedule.
|
|
338
|
+
\`stack\` | Blocks, one above another | A slide carrying two layouts, such as a diagram above columns.
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
# Composition @layout-composition
|
|
342
|
+
{
|
|
343
|
+
\`split\` and \`stack\` render each child scope as a *block*, and a
|
|
344
|
+
block reads its own \`config:\` line. That is how one slide carries a
|
|
345
|
+
pipeline above a set of numbered columns, or prose beside a
|
|
346
|
+
timeline, without a bespoke layout for the combination.
|
|
347
|
+
|
|
348
|
+
```
|
|
349
|
+
# How a request is served {
|
|
350
|
+
config: stack
|
|
351
|
+
|
|
352
|
+
rule: true
|
|
353
|
+
|
|
354
|
+
kicker: THE PATH
|
|
355
|
+
|
|
356
|
+
# @paths {
|
|
357
|
+
config: pipeline
|
|
358
|
+
|
|
359
|
+
# Cached {
|
|
360
|
+
accent: primary
|
|
361
|
+
|
|
362
|
+
{[.]
|
|
363
|
+
- Request
|
|
364
|
+
- **Edge hit**
|
|
365
|
+
- Response
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
# @detail {
|
|
371
|
+
config: columns
|
|
372
|
+
|
|
373
|
+
numbered: true
|
|
374
|
+
|
|
375
|
+
# The hot path {
|
|
376
|
+
One hop, no origin round trip.
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
# The cold path {
|
|
380
|
+
Two hops, and the origin does the work.
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
Nesting stops there. A block inside a block is ordinary content.
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
# Pipeline, and marking meaning @layout-pipeline
|
|
390
|
+
{
|
|
391
|
+
A pipeline row is a child scope: its heading is the row label and
|
|
392
|
+
its bullet list is the steps. **A step written entirely in bold is
|
|
393
|
+
marked** and takes the row's accent; every other step is neutral.
|
|
394
|
+
|
|
395
|
+
The distinction is semantic. Where a slide sets two paths against
|
|
396
|
+
each other, the marked steps are the ones a path cannot avoid and
|
|
397
|
+
the unmarked ones are the stages both paths share — so the reader
|
|
398
|
+
counts marks rather than reading a caption. The author marks what
|
|
399
|
+
is required; the theme decides what required looks like.
|
|
400
|
+
Restyling the deck must not lose that, which is why markedness
|
|
401
|
+
lives in the source rather than in a colour.
|
|
402
|
+
|
|
403
|
+
Set the row's accent with \`accent:\`. A theme may supply a default
|
|
404
|
+
— the built-in theme alternates between its first two accents —
|
|
405
|
+
but an explicit \`accent:\` always wins, so a deck that states its
|
|
406
|
+
accents is safe against a theme change.
|
|
407
|
+
|
|
408
|
+
\`arrow:\` sets the glyph drawn between steps, if the default arrow
|
|
409
|
+
is wrong for the diagram.
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
# Matrix @layout-matrix
|
|
413
|
+
{
|
|
414
|
+
A matrix slide holds one table. Column headings alternate between
|
|
415
|
+
two accents so a wide table stays scannable, and one row can be
|
|
416
|
+
picked out with \`highlight:\` — either \`last\`, or text the row's
|
|
417
|
+
first cell contains. A name that several rows share highlights all
|
|
418
|
+
of them, so pick something specific to the row you mean.
|
|
419
|
+
|
|
420
|
+
Within a cell, \`**bold**\` marks the name and \`*italic*\` marks the
|
|
421
|
+
trailing qualifier, which themes set smaller and dimmer. That keeps
|
|
422
|
+
a first column like **Beta Compute** *Series C, shipping* legible
|
|
423
|
+
as two pieces of information rather than one run-on line.
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
# Rows and bars @layout-rows
|
|
427
|
+
{
|
|
428
|
+
A \`rows\` child carries up to four parts: the automatic index when
|
|
429
|
+
the layout sets \`numbered: true\`, the heading as the label, the
|
|
430
|
+
content as the body, and \`value:\` as the right-hand figure.
|
|
431
|
+
\`variant: mono\` turns the label into a monospace accent, which is
|
|
432
|
+
what makes a timeline; \`variant: ledger\` drops the body and leaves
|
|
433
|
+
a label and a figure.
|
|
434
|
+
|
|
435
|
+
A \`bars\` child is a label, a \`value:\` and a note. Bars are scaled
|
|
436
|
+
against the largest numeric value in the set, so \`4,200 docs\` and
|
|
437
|
+
\`270 docs\` produce the right proportion without the author
|
|
438
|
+
computing percentages. Set \`fill:\` on a bar to override that.
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
# Images @layout-images
|
|
442
|
+
{
|
|
443
|
+
Images use the ordinary inline form, \`\`, inside
|
|
444
|
+
whichever cell they belong to. In a \`columns\` slide with
|
|
445
|
+
\`variant: card\`, an image at the top of each column with a heading
|
|
446
|
+
and a line of body beneath gives the standard figure row.
|
|
447
|
+
|
|
448
|
+
Paths are resolved relative to the \`.sdoc\` file. They are embedded
|
|
449
|
+
in the PPTX export; a remote URL is left out of it, and the build
|
|
450
|
+
says which.
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
242
454
|
# Drilldown Slides @drilldown
|
|
243
455
|
{
|
|
244
456
|
A slide deck is normally a 1D spine: Right and Left move along it. A
|
|
@@ -250,14 +462,14 @@
|
|
|
250
462
|
# Syntax @drilldown-syntax
|
|
251
463
|
{
|
|
252
464
|
```
|
|
253
|
-
#
|
|
465
|
+
# How the cache works @cache {
|
|
254
466
|
Main spine content.
|
|
255
467
|
|
|
256
|
-
#
|
|
468
|
+
# Eviction policy @eviction :detail {
|
|
257
469
|
Detail slide one.
|
|
258
470
|
}
|
|
259
471
|
|
|
260
|
-
#
|
|
472
|
+
# Cold-start behaviour @cold-start :detail {
|
|
261
473
|
Detail slide two.
|
|
262
474
|
}
|
|
263
475
|
|
|
@@ -325,7 +537,102 @@
|
|
|
325
537
|
\`theme.css\` — all visual styling (typography, colours, spacing, layouts).
|
|
326
538
|
|
|
327
539
|
\`theme.js\` (optional) — runtime behaviour (keyboard nav, touch support,
|
|
328
|
-
slide counter).
|
|
540
|
+
slide counter). A theme that ships none inherits the default runtime,
|
|
541
|
+
so most themes should omit it.
|
|
542
|
+
|
|
543
|
+
\`theme.json\` (optional) — the design box and the print page.
|
|
544
|
+
|
|
545
|
+
Assets (optional) — fonts and images the CSS refers to, in any
|
|
546
|
+
subdirectory.
|
|
547
|
+
|
|
548
|
+
# The design box @theme-box
|
|
549
|
+
{
|
|
550
|
+
Slides are laid out at a fixed size and the whole slide is then
|
|
551
|
+
scaled to fill the window, so the author's layout is preserved
|
|
552
|
+
verbatim at every window size and the screen and the PDF are the
|
|
553
|
+
same geometry by construction.
|
|
554
|
+
|
|
555
|
+
\`theme.json\` declares that size, and may declare the default fit
|
|
556
|
+
mode (see [Aspect Ratio and Fit](#fit)). The box in CSS pixels and
|
|
557
|
+
the page in inches must agree at 96 dpi, or the PDF clips:
|
|
558
|
+
|
|
559
|
+
```
|
|
560
|
+
{
|
|
561
|
+
"name": "wide-dark",
|
|
562
|
+
"slide": { "width": 1920, "height": 1080 },
|
|
563
|
+
"page": { "width": 20, "height": 11.25 },
|
|
564
|
+
"fit": "contain",
|
|
565
|
+
"fonts": { "display": "Georgia", "body": "Helvetica" }
|
|
566
|
+
}
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
With no \`theme.json\` a theme gets 1280 by 720, which is 13.333 by
|
|
570
|
+
7.5 inches — the same 16:9 proportion.
|
|
571
|
+
|
|
572
|
+
\`fonts\` names the typefaces the PPTX export falls back to when a
|
|
573
|
+
CSS font stack resolves to a generic family. It has no effect on
|
|
574
|
+
the HTML.
|
|
575
|
+
|
|
576
|
+
Every length in a theme's CSS is a pixel value at the design size.
|
|
577
|
+
A theme written against a 1920 by 1080 box sets a 68px heading and
|
|
578
|
+
means 68px on a 1920-wide slide, whatever the window is doing.
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
# Fonts and other assets @theme-assets
|
|
582
|
+
{
|
|
583
|
+
A theme may ship web fonts, background images or textures beside
|
|
584
|
+
its CSS and refer to them with ordinary relative URLs:
|
|
585
|
+
|
|
586
|
+
```
|
|
587
|
+
@font-face {
|
|
588
|
+
font-family: "Deck Sans";
|
|
589
|
+
src: url("fonts/deck-sans-latin.woff2") format("woff2");
|
|
590
|
+
}
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
The builder rewrites every relative \`url()\` in \`theme.css\` to a
|
|
594
|
+
\`data:\` URI, so the built deck is one file that carries its own
|
|
595
|
+
typefaces. Ship only fonts whose licence allows redistribution —
|
|
596
|
+
the SIL Open Font License does. It renders the same offline, on a machine without the
|
|
597
|
+
fonts installed, and inside headless Chrome during export —
|
|
598
|
+
which matters, because a PDF built against a fallback font is a
|
|
599
|
+
PDF with the wrong line breaks.
|
|
600
|
+
|
|
601
|
+
Absolute URLs, protocol-relative URLs and existing \`data:\` URIs
|
|
602
|
+
are left alone, and a path escaping the theme directory is
|
|
603
|
+
refused and reported.
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
# Writing against the layouts @theme-classes
|
|
607
|
+
{
|
|
608
|
+
A slide carries \`layout-<name>\` for whatever \`config:\` named, plus
|
|
609
|
+
\`accent-<name>\` if the slide set one. Target those. The bare layout
|
|
610
|
+
name is also emitted for \`center\` and \`two-column\` alone, because
|
|
611
|
+
themes written before \`layout-*\` existed rely on it; a theme that
|
|
612
|
+
styled some other layout by its bare name must move to
|
|
613
|
+
\`layout-<name>\`.
|
|
614
|
+
|
|
615
|
+
The head and body are wrapped in \`.slide-head\` and \`.slide-body\`,
|
|
616
|
+
both \`display: contents\` by default, so the *boxes* a theme sees
|
|
617
|
+
are the boxes it always saw: the heading and the content lay out
|
|
618
|
+
as direct children of the slide. A theme that wants a real header
|
|
619
|
+
band, or a body that takes the remaining height, overrides those
|
|
620
|
+
two rules.
|
|
621
|
+
|
|
622
|
+
**The DOM did change, even though the layout did not.**
|
|
623
|
+
\`display: contents\` removes a box, not an element, so a selector
|
|
624
|
+
written with a child combinator no longer matches: \`.slide > h2\`
|
|
625
|
+
and \`.slide > p\` have to become \`.slide h2\` and \`.slide p\`, or
|
|
626
|
+
name the wrapper. The same goes for \`:first-child\` and
|
|
627
|
+
\`:nth-child\` counted over a slide's children. Descendant
|
|
628
|
+
selectors are unaffected.
|
|
629
|
+
|
|
630
|
+
Structured layouts emit stable class names inside the body:
|
|
631
|
+
\`.columns > .column\`, \`.stats > .stat\`, \`.pipeline > .pipe-row\`,
|
|
632
|
+
\`.matrix\`, \`.rows > .row\`, \`.bars > .bar\`, \`.split > .pane\`,
|
|
633
|
+
\`.stack > .stack-block\`. A theme is free to style only the ones it
|
|
634
|
+
uses.
|
|
635
|
+
}
|
|
329
636
|
|
|
330
637
|
# Built-in Default Theme @default-theme
|
|
331
638
|
{
|
|
@@ -367,6 +674,109 @@
|
|
|
367
674
|
}
|
|
368
675
|
}
|
|
369
676
|
|
|
677
|
+
# Aspect Ratio and Fit @fit
|
|
678
|
+
{
|
|
679
|
+
A deck is laid out at one fixed size — the theme's design box — and the
|
|
680
|
+
whole slide is then scaled to meet the window. A window is rarely the
|
|
681
|
+
slide's exact shape, and what happens in that case is a build-time
|
|
682
|
+
choice:
|
|
683
|
+
|
|
684
|
+
{[table]
|
|
685
|
+
\`--fit\` | What happens off-ratio | Cost
|
|
686
|
+
\`contain\` | Scale to fit; the remainder is letterboxed | Unused screen at the edges
|
|
687
|
+
\`cover\` | Scale to fill; the overflow is cropped | Content near an edge is lost, including the footer
|
|
688
|
+
\`stretch\` | Scale each axis to the window | The slide is distorted
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
\`contain\` is the default and is almost always the right answer: the
|
|
692
|
+
deck keeps the proportions it was designed in, and nothing is lost or
|
|
693
|
+
misshapen. A theme may set its own default with \`"fit"\` in
|
|
694
|
+
\`theme.json\`, and \`--fit\` on the command line overrides it.
|
|
695
|
+
|
|
696
|
+
# Make the letterbox visible @fit-letterbox
|
|
697
|
+
{
|
|
698
|
+
With \`contain\`, the area the slide does not cover is painted with
|
|
699
|
+
\`--sdoc-letterbox\`. **A theme must not leave that equal to its own
|
|
700
|
+
slide background.** If it does, the slide has no visible edge, and
|
|
701
|
+
on an off-ratio window anything pinned to the bottom of the slide —
|
|
702
|
+
the footer, a footnote — appears to float in the middle of the
|
|
703
|
+
window instead of sitting on the slide's edge. Nothing is
|
|
704
|
+
misplaced; there is simply no edge to see it against.
|
|
705
|
+
|
|
706
|
+
Set the two apart:
|
|
707
|
+
|
|
708
|
+
```
|
|
709
|
+
:root { --sdoc-letterbox: #020202; } /* behind the slide */
|
|
710
|
+
body { background: var(--sdoc-letterbox); }
|
|
711
|
+
.slide { background: #101010; } /* the slide itself */
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
A hairline helps further on a dark theme, where the two grounds are
|
|
715
|
+
necessarily close:
|
|
716
|
+
|
|
717
|
+
```
|
|
718
|
+
.slide { box-shadow: 0 0 0 1px #1E1E1E; }
|
|
719
|
+
```
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
# For theme runtimes @fit-runtime
|
|
723
|
+
{
|
|
724
|
+
The renderer writes the mode to \`<html data-sdoc-fit>\` and the
|
|
725
|
+
theme runtime reads it, publishing \`--sdoc-slide-scale\` and
|
|
726
|
+
\`--sdoc-slide-scale-y\` on \`:root\`. Only \`stretch\` ever sets them
|
|
727
|
+
to different values.
|
|
728
|
+
|
|
729
|
+
\`--sdoc-slide-scale-y\` defaults to \`--sdoc-slide-scale\`, so a
|
|
730
|
+
theme shipping its own \`theme.js\` that writes only the one
|
|
731
|
+
variable still scales uniformly rather than collapsing vertically.
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
# PowerPoint and Google Slides Export @pptx-export
|
|
736
|
+
{
|
|
737
|
+
\`--pptx\` writes a PowerPoint file. Drive imports it as a native Google
|
|
738
|
+
Slides deck: upload it, then **File > Open with > Google Slides**, or
|
|
739
|
+
drag it into \`slides.google.com\`. That is the export route rather than
|
|
740
|
+
the Slides API because it needs no credentials in the toolchain, and
|
|
741
|
+
because the result is a useful file on its own.
|
|
742
|
+
|
|
743
|
+
# How it works @pptx-mechanism
|
|
744
|
+
{
|
|
745
|
+
The exporter has no layout engine. It builds the HTML deck, opens
|
|
746
|
+
it in headless Chrome, and asks the browser where every box, rule,
|
|
747
|
+
image and run of text ended up. Each of those becomes one
|
|
748
|
+
absolutely positioned shape in the exported file.
|
|
749
|
+
|
|
750
|
+
The consequence worth knowing: **the CSS is the single source of
|
|
751
|
+
layout truth**. A new layout, a new theme, a change to a margin —
|
|
752
|
+
all of it exports correctly without the exporter being taught
|
|
753
|
+
anything, because the exporter only ever reads the result.
|
|
754
|
+
|
|
755
|
+
Absolute positioning is also how a designed deck is built by hand.
|
|
756
|
+
The exported file is loose shapes on one blank layout, which is
|
|
757
|
+
what a designer would hand over, and it stays editable in Slides.
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
# What carries across @pptx-fidelity
|
|
761
|
+
{
|
|
762
|
+
Position, size, typeface, size, weight, italic, colour, letter
|
|
763
|
+
spacing, alignment and exact line spacing, per run. Fills,
|
|
764
|
+
borders, corner radii and alpha. Images, embedded from local paths
|
|
765
|
+
or \`data:\` URIs. Slide backgrounds. Speaker notes, as notes.
|
|
766
|
+
|
|
767
|
+
A border on only some sides is exported as a filled bar per side
|
|
768
|
+
rather than an outlined box, so a hairline under a heading is a
|
|
769
|
+
hairline rather than a rectangle with three invisible edges.
|
|
770
|
+
|
|
771
|
+
What does not carry: web fonts are named, not embedded, so the
|
|
772
|
+
fonts a theme uses must be available to the viewer. Choosing faces
|
|
773
|
+
that are on Google Fonts is the reliable route, because Slides
|
|
774
|
+
resolves those. Remote images are skipped and reported. Mermaid
|
|
775
|
+
diagrams and KaTeX export as the text and shapes the browser drew,
|
|
776
|
+
not as editable objects.
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
370
780
|
# Full Example @full-example
|
|
371
781
|
{
|
|
372
782
|
A complete slide deck demonstrating all features:
|
|
@@ -489,7 +899,18 @@
|
|
|
489
899
|
it will be rendered as regular text.
|
|
490
900
|
|
|
491
901
|
**Using config on the document root.** \`config:\` only works on slide
|
|
492
|
-
scopes (direct children of the root),
|
|
902
|
+
scopes (direct children of the root), and on child scopes in a
|
|
903
|
+
\`split\` or \`stack\` — not on the root itself.
|
|
904
|
+
|
|
905
|
+
**Putting content in a structured layout's slide scope.** In
|
|
906
|
+
\`columns\`, \`stats\`, \`rows\` and the rest, the *child scopes* are the
|
|
907
|
+
content. A paragraph written directly in the slide scope appears above
|
|
908
|
+
the structure, which is occasionally what you want and usually not —
|
|
909
|
+
\`lede:\` is the way to put a line under the title.
|
|
910
|
+
|
|
911
|
+
**Expecting a bullet list to become a pipeline.** A \`pipeline\` slide's
|
|
912
|
+
steps are the items of a bullet list inside a *child scope*, one scope
|
|
913
|
+
per row. A list written directly in the slide scope is just a list.
|
|
493
914
|
|
|
494
915
|
**Forgetting the @notes id.** Speaker notes require the \`@notes\` id
|
|
495
916
|
on the child scope heading. Without it, the scope renders as a visible
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@entropicwarrior/sdoc",
|
|
3
3
|
"displayName": "SDOC - Docs for Human/Agent Teams",
|
|
4
4
|
"description": "A plain-text documentation format with explicit brace scoping — deterministic parsing, AI-agent efficiency, and 10-50x token savings vs Markdown.",
|
|
5
|
-
"version": "0.2.
|
|
5
|
+
"version": "0.2.19",
|
|
6
6
|
"publisher": "entropicwarrior-msenfin",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
@@ -28,6 +28,9 @@
|
|
|
28
28
|
".": "./index.js",
|
|
29
29
|
"./slides": "./src/slide-renderer.js",
|
|
30
30
|
"./slide-pdf": "./src/slide-pdf.js",
|
|
31
|
+
"./slide-pptx": "./src/slide-pptx.js",
|
|
32
|
+
"./slide-geometry": "./src/slide-geometry.js",
|
|
33
|
+
"./theme": "./src/theme.js",
|
|
31
34
|
"./notion": "./src/notion-renderer.js",
|
|
32
35
|
"./knowledge": "./knowledge.js"
|
|
33
36
|
},
|