@kamishibai/sdk 0.1.1

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.
Files changed (136) hide show
  1. package/README.md +192 -0
  2. package/package.json +54 -0
  3. package/src/blocks/board.js +210 -0
  4. package/src/blocks/callout.js +63 -0
  5. package/src/blocks/code.js +28 -0
  6. package/src/blocks/deck.js +76 -0
  7. package/src/blocks/diagram.js +265 -0
  8. package/src/blocks/element.js +51 -0
  9. package/src/blocks/graph.js +264 -0
  10. package/src/blocks/grid.js +156 -0
  11. package/src/blocks/index.js +106 -0
  12. package/src/blocks/list.js +50 -0
  13. package/src/blocks/placement.js +119 -0
  14. package/src/blocks/prose.js +28 -0
  15. package/src/blocks/quote.js +25 -0
  16. package/src/blocks/raw.js +47 -0
  17. package/src/blocks/registry.js +158 -0
  18. package/src/blocks/schema-parts.js +19 -0
  19. package/src/blocks/section.js +53 -0
  20. package/src/blocks/slide.js +104 -0
  21. package/src/blocks/stat.js +83 -0
  22. package/src/blocks/table.js +50 -0
  23. package/src/blocks/timeline.js +80 -0
  24. package/src/cli/commands/close.js +51 -0
  25. package/src/cli/commands/comments.js +73 -0
  26. package/src/cli/commands/debug.js +34 -0
  27. package/src/cli/commands/example.js +22 -0
  28. package/src/cli/commands/export.js +10 -0
  29. package/src/cli/commands/init.js +53 -0
  30. package/src/cli/commands/lint.js +93 -0
  31. package/src/cli/commands/list.js +54 -0
  32. package/src/cli/commands/open.js +31 -0
  33. package/src/cli/commands/promote.js +38 -0
  34. package/src/cli/commands/render.js +31 -0
  35. package/src/cli/commands/replay.js +49 -0
  36. package/src/cli/commands/schema.js +10 -0
  37. package/src/cli/commands/serve.js +178 -0
  38. package/src/cli/commands/setup.js +64 -0
  39. package/src/cli/commands/snapshot.js +29 -0
  40. package/src/cli/commands/templates.js +75 -0
  41. package/src/cli/deliver.js +54 -0
  42. package/src/cli/emit.js +29 -0
  43. package/src/cli/format.js +153 -0
  44. package/src/cli/index.js +365 -0
  45. package/src/cli/registry.js +18 -0
  46. package/src/core/blocks.js +147 -0
  47. package/src/core/diagram.js +282 -0
  48. package/src/core/errors.js +156 -0
  49. package/src/core/example.js +109 -0
  50. package/src/core/ir.js +62 -0
  51. package/src/core/lint-gates.js +427 -0
  52. package/src/core/lint.js +281 -0
  53. package/src/core/scan.js +84 -0
  54. package/src/core/schema.js +88 -0
  55. package/src/core/spec-check.js +33 -0
  56. package/src/core/validate.js +44 -0
  57. package/src/core/version.js +18 -0
  58. package/src/core/vocabulary.js +140 -0
  59. package/src/delivery/atomic.js +71 -0
  60. package/src/delivery/comments.js +180 -0
  61. package/src/delivery/home.js +70 -0
  62. package/src/delivery/open.js +31 -0
  63. package/src/delivery/project.js +141 -0
  64. package/src/delivery/read.js +109 -0
  65. package/src/delivery/run.js +95 -0
  66. package/src/delivery/scaffold-blueprints.js +728 -0
  67. package/src/delivery/store.js +219 -0
  68. package/src/delivery/template-extensions.js +183 -0
  69. package/src/delivery/template-format.js +112 -0
  70. package/src/delivery/template-package.js +376 -0
  71. package/src/delivery/template-promote.js +240 -0
  72. package/src/delivery/template-scaffold.js +181 -0
  73. package/src/delivery/templates.js +192 -0
  74. package/src/delivery/toml.js +195 -0
  75. package/src/delivery/write.js +35 -0
  76. package/src/export/browser.js +130 -0
  77. package/src/export/index.js +96 -0
  78. package/src/export/pdf.js +25 -0
  79. package/src/export/png.js +40 -0
  80. package/src/export/pptx.js +48 -0
  81. package/src/export/slides.js +33 -0
  82. package/src/export/snapshot.js +33 -0
  83. package/src/layouts/article.js +103 -0
  84. package/src/layouts/canvas.js +144 -0
  85. package/src/layouts/card.js +128 -0
  86. package/src/layouts/deck.js +88 -0
  87. package/src/layouts/index.js +90 -0
  88. package/src/layouts/one-page.js +161 -0
  89. package/src/layouts/registry.js +251 -0
  90. package/src/layouts/resume.js +172 -0
  91. package/src/layouts/template-index.js +78 -0
  92. package/src/parser/artifact.js +38 -0
  93. package/src/parser/container.js +103 -0
  94. package/src/parser/index.js +223 -0
  95. package/src/parser/tokens.js +265 -0
  96. package/src/render/board-filter.client.js +80 -0
  97. package/src/render/compile.js +29 -0
  98. package/src/render/context.js +98 -0
  99. package/src/render/element.js +32 -0
  100. package/src/render/fonts.js +129 -0
  101. package/src/render/graph-hover.client.js +148 -0
  102. package/src/render/html.js +52 -0
  103. package/src/render/index.js +241 -0
  104. package/src/render/measure.js +60 -0
  105. package/src/render/placement.js +136 -0
  106. package/src/render/playback.client.js +74 -0
  107. package/src/render/scale-to-fit.client.js +136 -0
  108. package/src/render/scale.js +41 -0
  109. package/src/render/skeleton.js +131 -0
  110. package/src/render/ssr.js +24 -0
  111. package/src/render/styles.js +56 -0
  112. package/src/render/templates.js +191 -0
  113. package/src/serve/daemon.js +117 -0
  114. package/src/serve/overlay.js +213 -0
  115. package/src/serve/protocol.js +36 -0
  116. package/src/serve/server.js +264 -0
  117. package/templates/kami/cards/components.js +40 -0
  118. package/templates/kami/cards/index.js +25 -0
  119. package/templates/kami/cards/manifest.js +67 -0
  120. package/templates/kami/cards/styles.css +389 -0
  121. package/templates/kami/long-form/components.js +102 -0
  122. package/templates/kami/long-form/index.js +25 -0
  123. package/templates/kami/long-form/manifest.js +87 -0
  124. package/templates/kami/long-form/styles.css +481 -0
  125. package/templates/kami/one-page/components.js +48 -0
  126. package/templates/kami/one-page/index.js +27 -0
  127. package/templates/kami/one-page/manifest.js +65 -0
  128. package/templates/kami/one-page/styles.css +375 -0
  129. package/templates/kami/resume/components.js +51 -0
  130. package/templates/kami/resume/index.js +27 -0
  131. package/templates/kami/resume/manifest.js +65 -0
  132. package/templates/kami/resume/styles.css +424 -0
  133. package/templates/kami/slides/components.js +41 -0
  134. package/templates/kami/slides/index.js +26 -0
  135. package/templates/kami/slides/manifest.js +64 -0
  136. package/templates/kami/slides/styles.css +406 -0
@@ -0,0 +1,424 @@
1
+ :root {
2
+ --backdrop: #2b2f3a;
3
+ --surface: #ffffff;
4
+ --accent: #1B365D;
5
+ --accent-soft: #dbe2ec;
6
+ --rule: #d9d5cb;
7
+ --text-primary: #23201a;
8
+ --text-secondary: #55503f;
9
+ --text-muted: #8a8371;
10
+ --code-bg: #f1eee5;
11
+ --warn: #8a5a12;
12
+ /* Sheet geometry is the `resume` layout's A4 logical canvas, shipped on the
13
+ markup as data-ksb-canvas (src/layouts/resume.js). Not restated here: a
14
+ second copy of a size is a copy free to drift from the one that decides
15
+ anything. Comments in this file are ASCII on purpose -- every distinct
16
+ character in a stylesheet pulls a font subset into every artifact. */
17
+ /* ksb:maxWidth --max-width */
18
+ /* ksb:measure --measure */
19
+ /* Declared means embedded (CONTRACT A4): only families that really ship with
20
+ the artifact are named here; the rest fall back to generic keywords. */
21
+ --serif: 'Noto Serif TC', serif;
22
+ --mono: monospace;
23
+ }
24
+
25
+ * {
26
+ box-sizing: border-box;
27
+ }
28
+
29
+ html,
30
+ body {
31
+ margin: 0;
32
+ padding: 0;
33
+ }
34
+
35
+ body {
36
+ background: var(--backdrop);
37
+ color: var(--text-primary);
38
+ font-family: var(--serif);
39
+ font-size: 15px;
40
+ line-height: 1.55;
41
+ -webkit-font-smoothing: antialiased;
42
+ }
43
+
44
+ /* The page box belongs to this layout rather than to the printer defaults.
45
+ This SDK's own PDF export prints A4 with 14mm margins (src/export/pdf.js),
46
+ which leaves a printable box narrower and shorter than one sheet -- so a
47
+ sheet drawn at its natural size would lose a strip off the right edge and
48
+ another off the bottom of every page, silently. Claiming the whole page box
49
+ back is what makes one sheet exactly one printed page. The sheet's own
50
+ padding is the margin a reader sees. */
51
+ @page {
52
+ size: A4;
53
+ margin: 0;
54
+ }
55
+
56
+ /* The document: a stack of sheets. Its width is not capped here -- a sheet
57
+ carries its own fixed logical width inline, so a narrower window scrolls
58
+ sideways rather than squeezing a canvas that is not allowed to reflow. */
59
+ .resume {
60
+ margin: 0 auto;
61
+ overflow-x: auto;
62
+ }
63
+
64
+ /* One sheet *is* the bounded canvas: its size arrives inline and the skeleton's
65
+ scale-to-fit asset scales it (src/render/scale-to-fit.client.js). Only the
66
+ skin lives here. Content starts at the top rather than being centred: a page
67
+ of a resume that is half full should look half full, not float.
68
+
69
+ No horizontal margin, and that is an assertion rather than an omission: the
70
+ skeleton already translates every canvas by its own offsetX, so a skin that
71
+ also centres the box centres it twice and the sheet drifts off to one side by
72
+ half the leftover width. Measured at 1920 wide: sheet centre landed at 1523
73
+ against a window centre of 960. Horizontal placement belongs to the skeleton,
74
+ which is the only party that knows the scale. */
75
+ .sheet {
76
+ padding: 72px 67px;
77
+ background: var(--surface);
78
+ overflow: hidden;
79
+ display: flex;
80
+ flex-direction: column;
81
+ box-shadow: 0 2px 18px rgba(0, 0, 0, 0.35);
82
+ }
83
+
84
+ /* Content region: capped by the sheet width minus the printer-safe margin the
85
+ padding above already reserves. */
86
+ .sheet-inner {
87
+ width: 100%;
88
+ max-width: var(--max-width);
89
+ margin: 0 auto;
90
+ overflow-y: auto;
91
+ max-height: 100%;
92
+ }
93
+
94
+ /* Running text keeps the measure: on paper the page and the column are two
95
+ numbers just as they are on a screen (CONTRACT C3). */
96
+ .prose,
97
+ .list,
98
+ .quote,
99
+ .callout {
100
+ max-width: var(--measure);
101
+ }
102
+
103
+ .masthead {
104
+ border-bottom: 2px solid var(--accent);
105
+ padding-bottom: 18px;
106
+ margin-bottom: 26px;
107
+ }
108
+
109
+ .masthead .doc-title {
110
+ font-size: 34px;
111
+ line-height: 1.15;
112
+ font-weight: 700;
113
+ margin: 0;
114
+ color: var(--text-primary);
115
+ letter-spacing: 0.02em;
116
+ }
117
+
118
+ .masthead .kicker {
119
+ font-size: 13px;
120
+ letter-spacing: 0.16em;
121
+ text-transform: uppercase;
122
+ color: var(--accent);
123
+ margin: 10px 0 0;
124
+ }
125
+
126
+ .masthead .byline {
127
+ margin: 10px 0 0;
128
+ font-size: 13px;
129
+ color: var(--text-secondary);
130
+ }
131
+
132
+ /* A sheet holds one chapter, so the section gives up its outer margins and
133
+ keeps only its inner rhythm. */
134
+ .sheet-inner > .section {
135
+ margin: 0;
136
+ }
137
+
138
+ .section {
139
+ margin: 0 0 18px;
140
+ }
141
+
142
+ .section > .section-title {
143
+ font-weight: 700;
144
+ color: var(--accent);
145
+ line-height: 1.3;
146
+ }
147
+
148
+ /* The band heading of a resume: small, ruled, and unmistakably a divider
149
+ between one part of a career and the next. */
150
+ .section-l1 > .section-title,
151
+ .section-l2 > .section-title {
152
+ font-size: 17px;
153
+ letter-spacing: 0.12em;
154
+ text-transform: uppercase;
155
+ margin: 0 0 14px;
156
+ padding-bottom: 6px;
157
+ border-bottom: 1px solid var(--rule);
158
+ }
159
+
160
+ .section .section-l2 > .section-title,
161
+ .section .section-l3 > .section-title {
162
+ font-size: 15px;
163
+ letter-spacing: 0;
164
+ text-transform: none;
165
+ border-bottom: 0;
166
+ padding-bottom: 0;
167
+ margin: 16px 0 6px;
168
+ color: var(--text-primary);
169
+ }
170
+
171
+ .section-l4 > .section-title,
172
+ .section-l5 > .section-title,
173
+ .section-l6 > .section-title {
174
+ font-size: 14px;
175
+ margin: 12px 0 6px;
176
+ color: var(--text-secondary);
177
+ }
178
+
179
+ .prose {
180
+ margin: 0 0 10px;
181
+ }
182
+
183
+ .prose:last-child {
184
+ margin-bottom: 0;
185
+ }
186
+
187
+ .prose a {
188
+ color: var(--accent);
189
+ text-underline-offset: 3px;
190
+ }
191
+
192
+ /* Lists arrive two ways -- a list block, and list markup pushed into prose by a
193
+ raw island -- and both get the same rules, or the same source would look
194
+ different depending on which door it came through. On this layout the list is
195
+ the workhorse: a career is a list. */
196
+ .prose ul,
197
+ .prose ol,
198
+ .list {
199
+ margin: 0 0 10px;
200
+ padding-left: 1.3em;
201
+ }
202
+
203
+ .prose li,
204
+ .list li {
205
+ margin: 0 0 5px;
206
+ }
207
+
208
+ .prose li:last-child,
209
+ .list li:last-child {
210
+ margin-bottom: 0;
211
+ }
212
+
213
+ .prose li::marker,
214
+ .list li::marker {
215
+ color: var(--text-muted);
216
+ }
217
+
218
+ .list .list {
219
+ margin: 5px 0 0;
220
+ }
221
+
222
+ .list li > .prose {
223
+ margin: 0;
224
+ }
225
+
226
+ .list li > .prose + * {
227
+ margin-top: 5px;
228
+ }
229
+
230
+ .prose code,
231
+ .callout code,
232
+ .quote code,
233
+ .table code {
234
+ font-family: var(--mono);
235
+ font-size: 0.9em;
236
+ background: var(--code-bg);
237
+ border-radius: 3px;
238
+ padding: 1px 4px;
239
+ }
240
+
241
+ .quote {
242
+ margin: 0 0 12px;
243
+ padding: 2px 0 2px 14px;
244
+ border-left: 3px solid var(--accent-soft);
245
+ color: var(--text-secondary);
246
+ }
247
+
248
+ .quote > .prose:last-child {
249
+ margin-bottom: 0;
250
+ }
251
+
252
+ .callout {
253
+ margin: 0 0 12px;
254
+ padding: 12px 14px;
255
+ background: var(--code-bg);
256
+ border-left: 4px solid var(--accent);
257
+ border-radius: 2px;
258
+ }
259
+
260
+ .callout-warn {
261
+ border-left-color: var(--warn);
262
+ }
263
+
264
+ .callout .callout-label {
265
+ display: block;
266
+ font-size: 10px;
267
+ letter-spacing: 0.18em;
268
+ text-transform: uppercase;
269
+ color: var(--accent);
270
+ margin-bottom: 5px;
271
+ }
272
+
273
+ .callout-warn .callout-label {
274
+ color: var(--warn);
275
+ }
276
+
277
+ .callout > .prose:last-child {
278
+ margin-bottom: 0;
279
+ }
280
+
281
+ .code {
282
+ margin: 0 0 12px;
283
+ padding: 12px 14px;
284
+ background: var(--code-bg);
285
+ border: 1px solid var(--rule);
286
+ border-radius: 4px;
287
+ overflow-x: auto;
288
+ font-family: var(--mono);
289
+ font-size: 13px;
290
+ line-height: 1.45;
291
+ }
292
+
293
+ .code code {
294
+ font-family: inherit;
295
+ }
296
+
297
+ .table-wrap {
298
+ margin: 0 0 12px;
299
+ overflow-x: auto;
300
+ }
301
+
302
+ .table {
303
+ width: 100%;
304
+ border-collapse: collapse;
305
+ font-size: 13px;
306
+ }
307
+
308
+ .table th,
309
+ .table td {
310
+ border-bottom: 1px solid var(--rule);
311
+ padding: 6px 8px;
312
+ text-align: left;
313
+ vertical-align: top;
314
+ }
315
+
316
+ .table th {
317
+ color: var(--accent);
318
+ font-weight: 700;
319
+ border-bottom: 2px solid var(--accent-soft);
320
+ }
321
+
322
+ .island {
323
+ margin: 0 0 12px;
324
+ }
325
+
326
+ /* diagram (CONTRACT D1) -- the geometry is computed by core/diagram.js and the
327
+ skin only colours it, with variables every Kami skin agrees on, so one spec
328
+ draws one picture rather than several that look alike. */
329
+ .diagram {
330
+ margin: 0 0 12px;
331
+ overflow-x: auto;
332
+ }
333
+
334
+ .diagram-svg {
335
+ display: block;
336
+ max-width: 100%;
337
+ height: auto;
338
+ font-family: var(--serif);
339
+ }
340
+
341
+ .diagram-node-box {
342
+ fill: var(--accent-soft);
343
+ stroke: var(--accent);
344
+ stroke-width: 1.5;
345
+ }
346
+
347
+ .diagram-node-label {
348
+ fill: var(--text-primary);
349
+ font-size: 13px;
350
+ }
351
+
352
+ .diagram-edge-line {
353
+ fill: none;
354
+ stroke: var(--accent);
355
+ stroke-width: 1.5;
356
+ }
357
+
358
+ .diagram-arrow {
359
+ fill: var(--accent);
360
+ }
361
+
362
+ .diagram-edge-label {
363
+ fill: var(--text-secondary);
364
+ font-size: 11px;
365
+ }
366
+
367
+ /* The foot of the last sheet, inside the canvas: on paper anything outside a
368
+ sheet is laid onto a page of its own. */
369
+ .colophon {
370
+ margin-top: auto;
371
+ padding-top: 18px;
372
+ font-size: 10px;
373
+ color: var(--text-muted);
374
+ letter-spacing: 0.06em;
375
+ text-align: right;
376
+ }
377
+
378
+ @media print {
379
+ body {
380
+ background: #fff;
381
+ }
382
+
383
+ /* scale-to-fit is a screen affordance. On paper (and in `export`, which asks
384
+ for the print form) the inline transform would shrink every sheet into a
385
+ corner of its page. The stacking shadow goes too: it is a screen cue that
386
+ these are sheets of paper, and on paper they already are.
387
+
388
+ The other three declarations undo what makes a sheet a *fixed frame* on
389
+ screen, and they are the difference between a resume and a truncated one.
390
+ On screen a sheet is exactly one canvas high and its inner region scrolls;
391
+ on paper there is no scrollbar to reach for, so the same three rules mean
392
+ that anything past the first page is painted nowhere and reported by
393
+ nothing. Measured before this was fixed: a one-sheet resume of 60 entries
394
+ exported to PDF as ONE page, the last line sitting 744px below the bottom
395
+ of the paper, exit 0, no message anywhere -- while the same artifact
396
+ scrolled to the end perfectly well in a browser.
397
+
398
+ `height: auto` is the load-bearing one of the three, and it needs
399
+ `!important` because the height arrives inline with the canvas. Control
400
+ measurement: keeping the fixed height and relaxing only the clipping still
401
+ printed one page -- a fixed-height box does not hand its overflow to the
402
+ next page, it just stops. `break-inside: avoid` is gone for the same
403
+ reason: a sheet with more than a page of content has to be allowed to
404
+ split, and a rule that says otherwise is a rule the browser ignores while
405
+ the reader believes it. */
406
+ .sheet {
407
+ transform: none !important;
408
+ box-shadow: none;
409
+ display: block;
410
+ overflow: visible;
411
+ height: auto !important;
412
+ }
413
+
414
+ .sheet-inner {
415
+ overflow: visible;
416
+ max-height: none;
417
+ }
418
+
419
+ /* One sheet *starts* one printed page -- and runs on to the next when it has
420
+ more than a page of content in it. */
421
+ .sheet + .sheet {
422
+ break-before: page;
423
+ }
424
+ }
@@ -0,0 +1,41 @@
1
+ import { el } from '../../../src/blocks/element.js'
2
+
3
+ /**
4
+ * Chrome of the Kami slides template.
5
+ *
6
+ * The deck frame and the slide frame belong to the `deck` and `slide` block
7
+ * modules; the *shape of the artifact* — that a deck-rooted document draws its
8
+ * deck and nothing else — belongs to the `deck` layout since F2a. What is left
9
+ * here is what only this template can decide: the wording of the deck chrome,
10
+ * and that the opening slide carries the document's own identity.
11
+ */
12
+
13
+ /**
14
+ * The opening slide carries the document's own identity (frontmatter title and
15
+ * kicker); every later slide carries only its compiled blocks (CONTRACT C4).
16
+ */
17
+ const slideMasthead = (meta) =>
18
+ el('header', { class: 'slide-masthead' }, [
19
+ meta.kicker ? el('p', { class: 'kicker' }, [meta.kicker]) : null,
20
+ el('h1', { class: 'deck-title' }, [meta.title]),
21
+ meta.author || meta.date
22
+ ? el('p', { class: 'byline' }, [[meta.author, meta.date].filter(Boolean).join(' · ')])
23
+ : null,
24
+ ])
25
+
26
+ export const chrome = Object.freeze({
27
+ /** Only the first slide is led by the document masthead. */
28
+ 'slide-lead': (position, ctx) => (position.index === 0 ? [slideMasthead(ctx.meta)] : []),
29
+
30
+ /**
31
+ * The progress readout starts at `1 / n` and is rewritten by the skeleton's
32
+ * playback script; the hint is this template's wording, in this template's
33
+ * language, and is the reason the deck frame itself carries no text.
34
+ */
35
+ 'deck-chrome': ({ total }) => [
36
+ el('footer', { class: 'deck-chrome' }, [
37
+ el('span', { class: 'deck-progress' }, [`1 / ${total}`]),
38
+ el('span', { class: 'deck-hint' }, ['方向鍵/空白鍵翻頁 · F 全螢幕 · Esc 離開']),
39
+ ]),
40
+ ],
41
+ })
@@ -0,0 +1,26 @@
1
+ import { readFileSync } from 'node:fs'
2
+ import { fileURLToPath } from 'node:url'
3
+ import { manifest, templateKey } from './manifest.js'
4
+ import { chrome } from './components.js'
5
+
6
+ const STYLES_PATH = fileURLToPath(new URL('./styles.css', import.meta.url))
7
+
8
+ /**
9
+ * Template package as consumed by the render layer.
10
+ *
11
+ * No `script`: playback is a skeleton asset supplied to every deck-rooted
12
+ * layout by `src/render/skeleton.js`, with no opt-out. No `root` either: the
13
+ * shape of a deck artifact is the `deck` 文體's. What is left here is paint and
14
+ * wording — which is the whole claim of wayfinder issue 13.
15
+ */
16
+ export default Object.freeze({
17
+ manifest,
18
+ key: templateKey,
19
+ chrome,
20
+ language: manifest.language,
21
+ /** Fonts subset into the artifact (SPEC §7.2 出廠字體堆疊). */
22
+ fonts: Object.freeze([
23
+ Object.freeze({ package: '@fontsource/noto-serif-tc', weights: Object.freeze(['400', '700']) }),
24
+ ]),
25
+ styles: () => readFileSync(STYLES_PATH, 'utf8'),
26
+ })
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Template package descriptor (SPEC §5.2 `[template]` section) for the deck
3
+ * family. `---` only becomes a page break under this key (CONTRACT C4).
4
+ */
5
+ export const manifest = Object.freeze({
6
+ namespace: 'kami',
7
+ name: 'slides',
8
+ version: '0.1.0',
9
+ description: 'Kami 簡報模板 — 16:9 單張版面,內建離線播放',
10
+ language: 'zh-TW',
11
+ /**
12
+ * The 文體 this skin is a skin *of* (CONTRACT C1) — and the reason the root
13
+ * form below is inherited rather than invented: every template on the `deck`
14
+ * layout requires a deck root, whether or not it remembers to say so.
15
+ */
16
+ layout: 'deck',
17
+ /**
18
+ * Required root form (CONTRACT C4). `blocks` cannot express this: every
19
+ * long-form type below is legal *inside* a slide, so a flat document tree
20
+ * passes the type check while this template draws only `deck.slides` — the
21
+ * whole document silently disappears. The root form is a separate claim.
22
+ */
23
+ root: 'deck',
24
+ blocks: Object.freeze([
25
+ 'doc',
26
+ 'deck',
27
+ 'slide',
28
+ 'section',
29
+ 'prose',
30
+ 'list',
31
+ 'quote',
32
+ 'callout',
33
+ 'code',
34
+ 'table',
35
+ 'raw',
36
+ 'diagram',
37
+ // F6a 四型資料 block(11 號票 P1「資料」)。五張 Kami 皮一起宣告:
38
+ // 詞彙表是准入規則,一張皮少宣告一種,同一份文件在它底下就會被
39
+ // KSB_TEMPLATE_BLOCK_UNSUPPORTED 擋掉——而那不是守門,是缺角。
40
+ 'stat',
41
+ 'timeline',
42
+ 'board',
43
+ 'graph',
44
+ ]),
45
+ /** 轉子/<型別>/config — see the long-form manifest for why wording lives here. */
46
+ blockConfig: Object.freeze({
47
+ callout: Object.freeze({ labels: Object.freeze({ note: 'NOTE', warn: 'WARNING' }) }),
48
+ }),
49
+ /**
50
+ * The applied state of the `deck` layout's geometry knobs, in CSS pixels.
51
+ *
52
+ * A deck is the case that makes the numbers obviously distinct. Since F2f
53
+ * there are three of them and each has a different job: the logical page is
54
+ * 1280×720 and belongs to the 文體 (it arrives with the layout, not from
55
+ * here); `maxWidth` 1120 is how wide the content region inside that page may
56
+ * grow (`--slide-measure` in styles.css); and a line of text still wants the
57
+ * same 740px ruler everything else uses. Collapsing any two of them is
58
+ * exactly the mistake CONTRACT C3 separates out.
59
+ */
60
+ maxWidth: 1120,
61
+ measure: 740,
62
+ })
63
+
64
+ export const templateKey = `${manifest.namespace}/${manifest.name}`