@bendyline/squisq 1.4.1 → 1.5.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.
- package/README.md +14 -1
- package/dist/{ContentContainer-DNx460y8.d.ts → ContentContainer-BXUlIf18.d.ts} +6 -2
- package/dist/{Doc-BeSeH2iX.d.ts → Doc-BBVGq1_9.d.ts} +922 -273
- package/dist/{ImageEditDoc-BTIvw0oq.d.ts → ImageEditDoc-FuyGtt6o.d.ts} +11 -4
- package/dist/{chunk-ZTX4PFFT.js → chunk-2OIBZYKP.js} +75 -2
- package/dist/chunk-2OIBZYKP.js.map +1 -0
- package/dist/chunk-2UQOHYE2.js +45 -0
- package/dist/chunk-2UQOHYE2.js.map +1 -0
- package/dist/chunk-6ATE2PSM.js +344 -0
- package/dist/chunk-6ATE2PSM.js.map +1 -0
- package/dist/{chunk-57CVQCFX.js → chunk-A4O7GIWE.js} +74 -23
- package/dist/chunk-A4O7GIWE.js.map +1 -0
- package/dist/{chunk-5WFRKURX.js → chunk-DLXZMS5K.js} +4 -2
- package/dist/chunk-DLXZMS5K.js.map +1 -0
- package/dist/chunk-ET53IIEP.js +1 -0
- package/dist/chunk-ET53IIEP.js.map +1 -0
- package/dist/chunk-HWVFJAAH.js +362 -0
- package/dist/chunk-HWVFJAAH.js.map +1 -0
- package/dist/{chunk-2TMAWB4Y.js → chunk-IMSCRLLV.js} +1 -1
- package/dist/chunk-IMSCRLLV.js.map +1 -0
- package/dist/{chunk-B4EEON3N.js → chunk-KKNUBQ6Y.js} +536 -103
- package/dist/chunk-KKNUBQ6Y.js.map +1 -0
- package/dist/chunk-LDQ2HJIX.js +596 -0
- package/dist/chunk-LDQ2HJIX.js.map +1 -0
- package/dist/chunk-LH7I6SH7.js +7208 -0
- package/dist/chunk-LH7I6SH7.js.map +1 -0
- package/dist/chunk-PGGGKYWG.js +1 -0
- package/dist/chunk-PGGGKYWG.js.map +1 -0
- package/dist/{chunk-7UDSRZKG.js → chunk-Q3ROPT5H.js} +35 -14
- package/dist/chunk-Q3ROPT5H.js.map +1 -0
- package/dist/chunk-QE7TWGVT.js +178 -0
- package/dist/chunk-QE7TWGVT.js.map +1 -0
- package/dist/chunk-RUDYOTA6.js +345 -0
- package/dist/chunk-RUDYOTA6.js.map +1 -0
- package/dist/{chunk-K32VJONL.js → chunk-T5UK6YOB.js} +41 -2
- package/dist/chunk-T5UK6YOB.js.map +1 -0
- package/dist/{chunk-3K5OG6KI.js → chunk-TEEEILMP.js} +412 -186
- package/dist/chunk-TEEEILMP.js.map +1 -0
- package/dist/{chunk-FR2RBTKO.js → chunk-TQWLI6S2.js} +93 -27
- package/dist/chunk-TQWLI6S2.js.map +1 -0
- package/dist/{chunk-WMOI7FN3.js → chunk-UY7KGQ5R.js} +12 -2
- package/dist/{chunk-WMOI7FN3.js.map → chunk-UY7KGQ5R.js.map} +1 -1
- package/dist/{chunk-3E5F2XMR.js → chunk-VWUFZ6ZG.js} +29 -2
- package/dist/chunk-VWUFZ6ZG.js.map +1 -0
- package/dist/chunk-ZLQKNOZQ.js +1 -0
- package/dist/chunk-ZLQKNOZQ.js.map +1 -0
- package/dist/doc/index.d.ts +5 -5
- package/dist/doc/index.js +135 -8
- package/dist/generate/index.d.ts +3 -74
- package/dist/generate/index.js +2 -7
- package/dist/icons/index.d.ts +3 -26
- package/dist/icons/index.js +13 -0
- package/dist/icons/inlineIconMarker.d.ts +1 -0
- package/dist/icons/inlineIconMarker.js +15 -0
- package/dist/icons/inlineIconMarker.js.map +1 -0
- package/dist/imageEdit/index.d.ts +12 -6
- package/dist/imageEdit/index.js +4 -1
- package/dist/index.d.ts +14 -11
- package/dist/index.js +265 -37
- package/dist/inlineIconMarker-CiE8Hlvz.d.ts +59 -0
- package/dist/jsonForm/index.d.ts +42 -1
- package/dist/jsonForm/index.js +9 -1
- package/dist/markdown/index.d.ts +228 -3
- package/dist/markdown/index.js +42 -7
- package/dist/recommend/index.d.ts +1 -1
- package/dist/recommend/index.js +3 -2
- package/dist/schemas/index.d.ts +28 -8
- package/dist/schemas/index.js +36 -8
- package/dist/spatial/index.d.ts +9 -4
- package/dist/spatial/index.js +1 -1
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.js +1 -1
- package/dist/story/index.d.ts +1021 -41
- package/dist/story/index.js +135 -8
- package/dist/{themeLibrary-BHjJ0Qx6.d.ts → themeLibrary-CehcJhzz.d.ts} +1 -1
- package/dist/timing/index.js +3 -5
- package/dist/transform/index.d.ts +48 -10
- package/dist/transform/index.js +17 -481
- package/dist/transform/index.js.map +1 -1
- package/dist/{types-BdZkdJ3z.d.ts → types-DlAZ7MW4.d.ts} +115 -1
- package/dist/versions/index.d.ts +1 -1
- package/package.json +6 -1
- package/src/__tests__/animationUtils.test.ts +40 -0
- package/src/__tests__/annotationCoercion.test.ts +243 -0
- package/src/__tests__/applyRenderStyle.test.ts +146 -0
- package/src/__tests__/atmosphereLayers.test.ts +108 -0
- package/src/__tests__/attrTokens.test.ts +162 -0
- package/src/__tests__/contentExtractor.test.ts +60 -0
- package/src/__tests__/coverBlock.test.ts +46 -1
- package/src/__tests__/customTemplateSample.test.ts +144 -0
- package/src/__tests__/customTemplatesFrontmatter.test.ts +236 -0
- package/src/__tests__/customThemesFrontmatter.test.ts +145 -0
- package/src/__tests__/diagramBlock.test.ts +122 -0
- package/src/__tests__/diagramLayout.test.ts +134 -0
- package/src/__tests__/drawing.test.ts +109 -0
- package/src/__tests__/drawingBlock.test.ts +124 -0
- package/src/__tests__/drawingLayout.test.ts +171 -0
- package/src/__tests__/geohash.test.ts +6 -5
- package/src/__tests__/getLayers.test.ts +6 -2
- package/src/__tests__/getLayersFallback.test.ts +103 -0
- package/src/__tests__/imageEditExportSvg.test.ts +70 -0
- package/src/__tests__/imageEditVersions.test.ts +72 -0
- package/src/__tests__/inlineIconMarker.test.ts +36 -0
- package/src/__tests__/inputDescriptors.test.ts +162 -0
- package/src/__tests__/jsonForm.tokens.test.ts +84 -0
- package/src/__tests__/layoutBlock.test.ts +83 -0
- package/src/__tests__/layoutLayout.test.ts +169 -0
- package/src/__tests__/markdown.test.ts +87 -0
- package/src/__tests__/markdownSanitize.test.ts +79 -0
- package/src/__tests__/markdownToDoc.test.ts +391 -2
- package/src/__tests__/mediaAnnotations.test.ts +91 -0
- package/src/__tests__/mediaSchedule.test.ts +118 -0
- package/src/__tests__/pandocAttrParse.test.ts +187 -0
- package/src/__tests__/resolveDocTheme.test.ts +55 -0
- package/src/__tests__/rootExports.test.ts +43 -0
- package/src/__tests__/shapeGeometry.test.ts +89 -0
- package/src/__tests__/shapeVocabulary.test.ts +133 -0
- package/src/__tests__/structuredData.test.ts +249 -0
- package/src/__tests__/templateAnnotationParse.test.ts +108 -0
- package/src/__tests__/templateMetadata.test.ts +31 -0
- package/src/__tests__/templates.test.ts +257 -4
- package/src/__tests__/themeCompile.test.ts +42 -0
- package/src/__tests__/themeValidator.test.ts +6 -0
- package/src/__tests__/transformV2.test.ts +137 -0
- package/src/__tests__/transitionNormalize.test.ts +61 -0
- package/src/__tests__/validateDoc.test.ts +260 -0
- package/src/doc/annotationBlocks.ts +117 -0
- package/src/doc/customTemplatesFrontmatter.ts +314 -0
- package/src/doc/customThemesFrontmatter.ts +95 -0
- package/src/doc/docToMarkdown.ts +104 -5
- package/src/doc/getLayers.ts +49 -17
- package/src/doc/index.ts +47 -1
- package/src/doc/markdownToDoc.ts +411 -13
- package/src/doc/mediaAnnotations.ts +100 -0
- package/src/doc/resolveDocTheme.ts +55 -0
- package/src/doc/standaloneAnnotation.ts +58 -0
- package/src/doc/structuredData.ts +301 -0
- package/src/doc/templateInputs.ts +240 -0
- package/src/doc/templates/__tests__/customTemplate.test.ts +170 -0
- package/src/doc/templates/__tests__/customTemplateRegistry.test.ts +110 -0
- package/src/doc/templates/accentImage.ts +30 -6
- package/src/doc/templates/captionUtils.ts +23 -0
- package/src/doc/templates/comparisonBar.ts +33 -18
- package/src/doc/templates/coverBlock.ts +35 -5
- package/src/doc/templates/customTemplate.ts +51 -0
- package/src/doc/templates/dataTable.ts +37 -19
- package/src/doc/templates/dateEvent.ts +41 -20
- package/src/doc/templates/definitionCard.ts +26 -18
- package/src/doc/templates/diagramBlock.ts +204 -0
- package/src/doc/templates/diagramLayout.ts +159 -0
- package/src/doc/templates/drawingBlock.ts +325 -0
- package/src/doc/templates/drawingLayout.ts +539 -0
- package/src/doc/templates/factCard.ts +54 -26
- package/src/doc/templates/fallbackBlock.ts +123 -0
- package/src/doc/templates/featureBlock.ts +20 -13
- package/src/doc/templates/fullBleedQuote.ts +18 -8
- package/src/doc/templates/imageWithCaption.ts +30 -15
- package/src/doc/templates/index.ts +225 -46
- package/src/doc/templates/inputDescriptors.ts +432 -0
- package/src/doc/templates/layoutBlock.ts +43 -0
- package/src/doc/templates/layoutLayout.ts +243 -0
- package/src/doc/templates/listBlock.ts +56 -30
- package/src/doc/templates/mapBlock.ts +15 -12
- package/src/doc/templates/metadata.ts +120 -0
- package/src/doc/templates/persistentLayers.ts +129 -11
- package/src/doc/templates/photoGrid.ts +22 -34
- package/src/doc/templates/pullQuote.ts +30 -12
- package/src/doc/templates/quoteBlock.ts +54 -29
- package/src/doc/templates/sectionHeader.ts +25 -11
- package/src/doc/templates/statHighlight.ts +39 -22
- package/src/doc/templates/titleBlock.ts +59 -21
- package/src/doc/templates/tokens/__tests__/resolveTokens.test.ts +487 -0
- package/src/doc/templates/tokens/resolveTokens.ts +453 -0
- package/src/doc/templates/twoColumn.ts +48 -30
- package/src/doc/templates/videoPullQuote.ts +22 -12
- package/src/doc/templates/videoWithCaption.ts +21 -15
- package/src/doc/utils/animationUtils.ts +267 -3
- package/src/doc/utils/applyRenderStyle.ts +113 -0
- package/src/doc/utils/imageTreatment.ts +70 -0
- package/src/doc/utils/nearest.ts +59 -0
- package/src/doc/utils/shapeGeometry.ts +464 -0
- package/src/doc/utils/themeUtils.ts +75 -1
- package/src/doc/validate.ts +575 -0
- package/src/generate/contentExtractor.ts +148 -35
- package/src/generate/index.ts +0 -3
- package/src/icons/index.ts +8 -0
- package/src/icons/inlineIconMarker.ts +73 -0
- package/src/imageEdit/export.ts +85 -2
- package/src/imageEdit/index.ts +1 -0
- package/src/imageEdit/persistence.ts +51 -0
- package/src/index.ts +2 -0
- package/src/jsonForm/index.ts +2 -0
- package/src/jsonForm/tokens.ts +78 -0
- package/src/markdown/annotationCoercion.ts +295 -0
- package/src/markdown/attrTokens.ts +241 -0
- package/src/markdown/convert.ts +229 -26
- package/src/markdown/index.ts +37 -0
- package/src/markdown/sanitize.ts +318 -0
- package/src/markdown/stringify.ts +96 -6
- package/src/markdown/types.ts +66 -0
- package/src/markdown/utils.ts +111 -2
- package/src/recommend/templates.ts +24 -0
- package/src/schemas/BlockTemplates.ts +133 -4
- package/src/schemas/CustomTemplates.ts +126 -0
- package/src/schemas/Doc.ts +387 -65
- package/src/schemas/ImageEditDoc.ts +11 -4
- package/src/schemas/Media.ts +169 -0
- package/src/schemas/Theme.ts +23 -1
- package/src/schemas/Transitions.ts +224 -0
- package/src/schemas/colorUtils.ts +33 -0
- package/src/schemas/fontStacks.ts +5 -2
- package/src/schemas/index.ts +3 -0
- package/src/schemas/themeCompile.ts +24 -5
- package/src/schemas/themeValidator.ts +49 -11
- package/src/schemas/themes/cinematic.json +69 -12
- package/src/schemas/themes/documentary.json +58 -11
- package/src/schemas/themes/gezellig.json +60 -11
- package/src/schemas/themes/magazine.json +54 -9
- package/src/schemas/themes/morning-light.json +52 -9
- package/src/schemas/themes/standard-dark.json +48 -13
- package/src/schemas/themes/standard.json +44 -12
- package/src/schemas/themes/tech-dark.json +65 -12
- package/src/spatial/Geohash.ts +52 -21
- package/src/storage/ContentContainer.ts +6 -2
- package/src/transform/applyTransform.ts +43 -4
- package/src/transform/index.ts +1 -0
- package/src/transform/registry.ts +44 -13
- package/src/transform/styles/dataDriven.ts +2 -1
- package/src/transform/styles/documentary.ts +2 -1
- package/src/transform/styles/magazine.ts +3 -1
- package/src/transform/styles/minimal.ts +2 -1
- package/src/transform/styles/narrative.ts +3 -1
- package/src/transform/templateSelector.ts +87 -11
- package/src/transform/types.ts +35 -2
- package/dist/chunk-2TMAWB4Y.js.map +0 -1
- package/dist/chunk-3E5F2XMR.js.map +0 -1
- package/dist/chunk-3K5OG6KI.js.map +0 -1
- package/dist/chunk-4X3JQXNM.js +0 -35
- package/dist/chunk-4X3JQXNM.js.map +0 -1
- package/dist/chunk-57CVQCFX.js.map +0 -1
- package/dist/chunk-5WFRKURX.js.map +0 -1
- package/dist/chunk-7UDSRZKG.js.map +0 -1
- package/dist/chunk-B4EEON3N.js.map +0 -1
- package/dist/chunk-FR2RBTKO.js.map +0 -1
- package/dist/chunk-H3AXU4MJ.js +0 -179
- package/dist/chunk-H3AXU4MJ.js.map +0 -1
- package/dist/chunk-K32VJONL.js.map +0 -1
- package/dist/chunk-KSWJR66U.js +0 -3706
- package/dist/chunk-KSWJR66U.js.map +0 -1
- package/dist/chunk-MYIH7FWD.js +0 -145
- package/dist/chunk-MYIH7FWD.js.map +0 -1
- package/dist/chunk-ZTX4PFFT.js.map +0 -1
- package/src/__tests__/slideshowGenerator.test.ts +0 -128
- package/src/generate/slideshowGenerator.ts +0 -273
package/src/schemas/Doc.ts
CHANGED
|
@@ -14,10 +14,28 @@
|
|
|
14
14
|
* has 3-6 MP3 files (intro + sections), and blocks are grouped by segment.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import type { Transition } from './Transitions.js';
|
|
18
|
+
export type { Transition, TransitionType, TransitionDirection } from './Transitions.js';
|
|
19
|
+
|
|
17
20
|
// ============================================
|
|
18
21
|
// Core Types
|
|
19
22
|
// ============================================
|
|
20
23
|
|
|
24
|
+
/**
|
|
25
|
+
* A directed connection from one block to another.
|
|
26
|
+
*
|
|
27
|
+
* Populated from a heading's Pandoc-style `{connectsTo=…}` attribute
|
|
28
|
+
* (e.g. `## Step 1 {#step1 connectsTo=foo:flow,bar}`). Each item is
|
|
29
|
+
* `target` or `target:type`. Used by diagram-style layouts that draw
|
|
30
|
+
* edges between blocks.
|
|
31
|
+
*/
|
|
32
|
+
export interface BlockConnection {
|
|
33
|
+
/** Target block id (matches another block's `id`). */
|
|
34
|
+
target: string;
|
|
35
|
+
/** Optional connection type/label (e.g., "flow", "requires"). */
|
|
36
|
+
type?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
21
39
|
/**
|
|
22
40
|
* Configuration for the Start/resting block shown before playback begins.
|
|
23
41
|
*/
|
|
@@ -38,6 +56,31 @@ export interface StartBlockConfig {
|
|
|
38
56
|
heroLicense?: string;
|
|
39
57
|
}
|
|
40
58
|
|
|
59
|
+
/**
|
|
60
|
+
* A structural problem detected while converting or validating a document.
|
|
61
|
+
*
|
|
62
|
+
* Diagnostics ride on `Doc.diagnostics` so any consumer — the editor, the
|
|
63
|
+
* CLI `validate` command, or an agent re-parsing its own output — gets the
|
|
64
|
+
* same feedback without watching the console. Conversion never throws for
|
|
65
|
+
* content problems; it degrades gracefully and records a diagnostic.
|
|
66
|
+
*/
|
|
67
|
+
export interface DocDiagnostic {
|
|
68
|
+
/** `error` = the author's intent could not be honored (e.g. unparseable
|
|
69
|
+
* data fence); `warning` = something looks wrong but rendering proceeds
|
|
70
|
+
* with a fallback (e.g. unknown template name); `info` = nothing is
|
|
71
|
+
* broken, but the author may want to know (e.g. a redundant annotation). */
|
|
72
|
+
severity: 'error' | 'warning' | 'info';
|
|
73
|
+
/** Stable machine-readable code (e.g. `unknown-template`, `duplicate-id`,
|
|
74
|
+
* `unresolved-connection`, `data-fence-parse`, `missing-asset`). */
|
|
75
|
+
code: string;
|
|
76
|
+
/** Human-readable description, including a suggestion when one exists. */
|
|
77
|
+
message: string;
|
|
78
|
+
/** Id of the block the problem belongs to, when attributable. */
|
|
79
|
+
blockId?: string;
|
|
80
|
+
/** 1-based line number in the markdown source, when known. */
|
|
81
|
+
line?: number;
|
|
82
|
+
}
|
|
83
|
+
|
|
41
84
|
/**
|
|
42
85
|
* A complete visual doc for an article.
|
|
43
86
|
*/
|
|
@@ -88,6 +131,52 @@ export interface Doc {
|
|
|
88
131
|
* Carries rendering hints like `document-render-as` and custom metadata.
|
|
89
132
|
*/
|
|
90
133
|
frontmatter?: Record<string, unknown>;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* User-defined block templates inlined into this doc.
|
|
137
|
+
*
|
|
138
|
+
* Populated from the markdown frontmatter key
|
|
139
|
+
* `squisq-custom-templates`. The template-expansion pipeline
|
|
140
|
+
* (`expandDocBlocks` in `doc/templates/index.ts`) merges these into
|
|
141
|
+
* the registry before walking blocks, so a heading annotated
|
|
142
|
+
* `{[myhero]}` resolves against a doc-defined template named `myhero`.
|
|
143
|
+
*
|
|
144
|
+
* Library templates (stored in localStorage on the editor side) are
|
|
145
|
+
* NOT auto-loaded here — applying a library template to a block
|
|
146
|
+
* copies its definition into this list so the doc remains
|
|
147
|
+
* self-sufficient for SSR and export.
|
|
148
|
+
*/
|
|
149
|
+
customTemplates?: import('./CustomTemplates.js').CustomTemplateDefinition[];
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* User-defined themes inlined into this doc.
|
|
153
|
+
*
|
|
154
|
+
* The theme analog of {@link Doc.customTemplates}. Populated from the
|
|
155
|
+
* markdown frontmatter key `squisq-custom-themes`. Exactly one is active
|
|
156
|
+
* at a time — selected by id via `squisq-theme` / {@link Doc.themeId},
|
|
157
|
+
* the doc-level counterpart of a block's `{[name]}` template annotation —
|
|
158
|
+
* but the payload is a list so a doc can carry a small catalog and stay
|
|
159
|
+
* self-sufficient for SSR / export. `resolveThemeForDoc(doc, id)` resolves
|
|
160
|
+
* against this list first (pure, doc-scoped) before built-ins, mirroring
|
|
161
|
+
* how `buildRegistry` resolves custom templates.
|
|
162
|
+
*/
|
|
163
|
+
customThemes?: import('./Theme.js').Theme[];
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Structural problems found while building this doc (unknown templates,
|
|
167
|
+
* unparseable data fences, duplicate ids, unresolved connections, …).
|
|
168
|
+
* Populated by `markdownToDoc()`; extended by `validateMarkdownDoc()`.
|
|
169
|
+
* Absent when the document is clean.
|
|
170
|
+
*/
|
|
171
|
+
diagnostics?: DocDiagnostic[];
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Document-spanning timed media (e.g. a full-length narration MP3/MP4),
|
|
175
|
+
* authored as a media annotation in the preamble (before the first
|
|
176
|
+
* heading) with `anchor=document`. Each clip is timed from the document
|
|
177
|
+
* start and may play across every block. See `resolveMediaSchedule`.
|
|
178
|
+
*/
|
|
179
|
+
documentMedia?: import('./Media.js').MediaClip[];
|
|
91
180
|
}
|
|
92
181
|
|
|
93
182
|
/**
|
|
@@ -98,15 +187,29 @@ export interface Doc {
|
|
|
98
187
|
* - `sourceHeading` references the original MarkdownHeading node
|
|
99
188
|
* - `contents` holds the body markdown between this heading and the next
|
|
100
189
|
* - `children` holds sub-heading blocks (e.g., H2s under an H1)
|
|
190
|
+
*
|
|
191
|
+
* Four adjacent fields carry template information — do not confuse them:
|
|
192
|
+
* - `template` — the *resolved* template id this block renders with.
|
|
193
|
+
* - `templateOverrides` — raw `{[…]}` inline params (always strings).
|
|
194
|
+
* - `templateData` — structured inputs from a data fence / GFM table
|
|
195
|
+
* (parsed types, not strings).
|
|
196
|
+
* - `sourceAnnotation.template` — the raw *requested* template name for a
|
|
197
|
+
* standalone-annotation block (before alias resolution).
|
|
198
|
+
* Merge order at render time: template defaults → `templateData` →
|
|
199
|
+
* `templateOverrides`.
|
|
101
200
|
*/
|
|
102
201
|
export interface Block {
|
|
103
|
-
/** Unique identifier for this block
|
|
202
|
+
/** Unique identifier for this block.
|
|
203
|
+
* Defaults to a slug derived from the heading text. May be overridden by
|
|
204
|
+
* a Pandoc-style `{#custom-id}` attribute on the heading. */
|
|
104
205
|
id: string;
|
|
105
206
|
|
|
106
|
-
/** When this block appears (seconds from start)
|
|
207
|
+
/** When this block appears (seconds from start).
|
|
208
|
+
* Overridden by a heading attribute `startTime=…` when present. */
|
|
107
209
|
startTime: number;
|
|
108
210
|
|
|
109
|
-
/** How long this block is visible (seconds)
|
|
211
|
+
/** How long this block is visible (seconds).
|
|
212
|
+
* Overridden by a heading attribute `duration=…` when present. */
|
|
110
213
|
duration: number;
|
|
111
214
|
|
|
112
215
|
/** Which audio segment this block belongs to (0-indexed) */
|
|
@@ -124,9 +227,39 @@ export interface Block {
|
|
|
124
227
|
/** Entry transition from previous block */
|
|
125
228
|
transition?: Transition;
|
|
126
229
|
|
|
127
|
-
/**
|
|
230
|
+
/** Resolved template id this block renders with (see the quartet note above). */
|
|
128
231
|
template?: string;
|
|
129
232
|
|
|
233
|
+
/**
|
|
234
|
+
* True when `template` was chosen by content-aware auto-picking
|
|
235
|
+
* (`markdownToDoc`'s `autoTemplates`) rather than authored. Ephemeral:
|
|
236
|
+
* `docToMarkdown` does not materialize auto-picked templates as heading
|
|
237
|
+
* annotations, keeping the markdown round-trip lossless.
|
|
238
|
+
*/
|
|
239
|
+
autoTemplate?: boolean;
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* True when this block was produced from a *standalone* `{[templateName …]}`
|
|
243
|
+
* annotation paragraph in another block's body (rather than from a heading).
|
|
244
|
+
* Such blocks have no `sourceHeading`; `docToMarkdown` re-emits their
|
|
245
|
+
* annotation as a synthesized paragraph before their `contents` so the
|
|
246
|
+
* markdown round-trips. See `annotationBlocks.ts`.
|
|
247
|
+
*
|
|
248
|
+
* Presence-marker: only ever `true` (never `false`). Test with
|
|
249
|
+
* `block.standaloneAnnotation` presence, not as a boolean toggle.
|
|
250
|
+
*/
|
|
251
|
+
standaloneAnnotation?: true;
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* The annotation a standalone block was built from — the raw (un-resolved)
|
|
255
|
+
* template name and its params, in author order. Round-tripped by
|
|
256
|
+
* `docToMarkdown` (via `serializeAnnotation`) and read by validation as the
|
|
257
|
+
* raw requested template name (symmetric with
|
|
258
|
+
* `sourceHeading.templateAnnotation`). Present only when
|
|
259
|
+
* `standaloneAnnotation` is true.
|
|
260
|
+
*/
|
|
261
|
+
sourceAnnotation?: { template?: string; params?: Record<string, string> };
|
|
262
|
+
|
|
130
263
|
/**
|
|
131
264
|
* Display title for template rendering.
|
|
132
265
|
* Extracted from the sourceHeading when the block is created by markdownToDoc().
|
|
@@ -161,12 +294,63 @@ export interface Block {
|
|
|
161
294
|
sourceHeading?: import('../markdown/types.js').MarkdownHeading;
|
|
162
295
|
|
|
163
296
|
/**
|
|
164
|
-
* Template overrides extracted from
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
297
|
+
* Template overrides extracted from a heading's `{[templateName key=value]}`
|
|
298
|
+
* annotation. Only carries template-specific params (e.g. `colorScheme=blue`).
|
|
299
|
+
* Block-level metadata lives in `x` / `y` / `connectsTo` / `metadata` and is
|
|
300
|
+
* sourced from the Pandoc-style `{#id .class key=value}` attribute block instead.
|
|
168
301
|
*/
|
|
169
302
|
templateOverrides?: Record<string, string>;
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Structured template inputs sourced from the block's body content:
|
|
306
|
+
* a ```json data / ```yaml data fence under the heading, or — for the
|
|
307
|
+
* `dataTable` template — the first GFM table in the section. Unlike
|
|
308
|
+
* `templateOverrides` (always strings), values here keep their parsed
|
|
309
|
+
* types (arrays, numbers, nested objects). Merge order at render time:
|
|
310
|
+
* template defaults → `templateData` → `templateOverrides`.
|
|
311
|
+
*/
|
|
312
|
+
templateData?: Record<string, unknown>;
|
|
313
|
+
|
|
314
|
+
// ── Block-level metadata from Pandoc-style `{#id .class key=value}` ──
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* X coordinate for diagram-style positioning (in author-defined units).
|
|
318
|
+
* Sourced from a heading attribute `x=…`.
|
|
319
|
+
*/
|
|
320
|
+
x?: number;
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Y coordinate for diagram-style positioning (in author-defined units).
|
|
324
|
+
* Sourced from a heading attribute `y=…`.
|
|
325
|
+
*/
|
|
326
|
+
y?: number;
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Outgoing connections to other blocks, by id. Sourced from a heading
|
|
330
|
+
* attribute `connectsTo=target1,target2:type,target3`.
|
|
331
|
+
*/
|
|
332
|
+
connectsTo?: BlockConnection[];
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* CSS-style class tokens from a heading's Pandoc attribute (e.g. `{.important .v2}`).
|
|
336
|
+
* Parsed and stored; downstream consumers may use them for styling or filtering.
|
|
337
|
+
*/
|
|
338
|
+
classes?: string[];
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Free-form metadata for heading attribute keys outside the typed registry
|
|
342
|
+
* (anything that isn't `x` / `y` / `connectsTo` / `startTime` / `duration`).
|
|
343
|
+
* Values are raw strings exactly as authored.
|
|
344
|
+
*/
|
|
345
|
+
metadata?: Record<string, string>;
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Timed media clips attached to this block, authored as body-level
|
|
349
|
+
* `{[audio …]}` / `{[video …]}` annotations. Each clip is timed relative
|
|
350
|
+
* to this block's `startTime` (via `startAt`) and optionally spills past
|
|
351
|
+
* the block's end. See `MediaClip` / `resolveMediaSchedule`.
|
|
352
|
+
*/
|
|
353
|
+
media?: import('./Media.js').MediaClip[];
|
|
170
354
|
}
|
|
171
355
|
|
|
172
356
|
// ============================================
|
|
@@ -177,7 +361,14 @@ export interface Block {
|
|
|
177
361
|
* A visual element within a block.
|
|
178
362
|
* Layers are composited back-to-front (first layer is background).
|
|
179
363
|
*/
|
|
180
|
-
export type Layer =
|
|
364
|
+
export type Layer =
|
|
365
|
+
| ImageLayer
|
|
366
|
+
| TextLayer
|
|
367
|
+
| ShapeLayer
|
|
368
|
+
| PathLayer
|
|
369
|
+
| MapLayer
|
|
370
|
+
| VideoLayer
|
|
371
|
+
| TableLayer;
|
|
181
372
|
|
|
182
373
|
interface BaseLayer {
|
|
183
374
|
/** Unique identifier for this layer */
|
|
@@ -190,6 +381,25 @@ interface BaseLayer {
|
|
|
190
381
|
animation?: Animation;
|
|
191
382
|
}
|
|
192
383
|
|
|
384
|
+
/**
|
|
385
|
+
* Photographic treatment applied to an image layer — a theme-level "grade"
|
|
386
|
+
* so the same photo looks native in every theme. Rendered as CSS filter
|
|
387
|
+
* functions, which behave identically in the browser player and headless
|
|
388
|
+
* frame capture (video/still export).
|
|
389
|
+
*/
|
|
390
|
+
export interface ImageTreatment {
|
|
391
|
+
/**
|
|
392
|
+
* mono: desaturate toward archival black & white.
|
|
393
|
+
* duotone: single-hue tint (hue taken from `color`).
|
|
394
|
+
* warm / cool: gentle temperature grade.
|
|
395
|
+
*/
|
|
396
|
+
type: 'none' | 'mono' | 'duotone' | 'warm' | 'cool';
|
|
397
|
+
/** Blend strength 0..1. Default 0.6. */
|
|
398
|
+
strength?: number;
|
|
399
|
+
/** Duotone tint color (themes default this to their primary). */
|
|
400
|
+
color?: string;
|
|
401
|
+
}
|
|
402
|
+
|
|
193
403
|
/**
|
|
194
404
|
* Image layer - displays an image with optional Ken Burns effect.
|
|
195
405
|
*/
|
|
@@ -206,6 +416,10 @@ export interface ImageLayer extends BaseLayer {
|
|
|
206
416
|
credit?: string;
|
|
207
417
|
/** License identifier (e.g., 'CC BY-SA 4.0') */
|
|
208
418
|
license?: string;
|
|
419
|
+
/** Theme-derived photographic grade (see ImageTreatment). */
|
|
420
|
+
treatment?: ImageTreatment;
|
|
421
|
+
/** Gaussian blur radius in px (background/atmosphere imagery). */
|
|
422
|
+
blur?: number;
|
|
209
423
|
};
|
|
210
424
|
}
|
|
211
425
|
|
|
@@ -215,16 +429,73 @@ export interface ImageLayer extends BaseLayer {
|
|
|
215
429
|
export interface TextLayer extends BaseLayer {
|
|
216
430
|
type: 'text';
|
|
217
431
|
content: {
|
|
218
|
-
/**
|
|
432
|
+
/**
|
|
433
|
+
* Plain text (supports \n for line breaks). Source of truth for plain
|
|
434
|
+
* consumers — PDF/markdown export, search, accessibility — and the SVG
|
|
435
|
+
* `<text>` fallback. When `html` is set, this is its plain-text
|
|
436
|
+
* projection and must be kept in sync.
|
|
437
|
+
*/
|
|
219
438
|
text: string;
|
|
439
|
+
/**
|
|
440
|
+
* Optional sanitized **inline** HTML for rich formatting (bold/italic/
|
|
441
|
+
* links, and — for layout textboxes — headings/lists). When present the
|
|
442
|
+
* renderer draws it via `<foreignObject>` instead of SVG `<text>`. Treated
|
|
443
|
+
* as untrusted and re-sanitized at render time. See `RichTextLayer` in
|
|
444
|
+
* `@bendyline/squisq-react`.
|
|
445
|
+
*/
|
|
446
|
+
html?: string;
|
|
220
447
|
/** Text styling */
|
|
221
448
|
style: TextStyle;
|
|
222
449
|
};
|
|
223
450
|
}
|
|
224
451
|
|
|
452
|
+
/**
|
|
453
|
+
* A two-stop linear gradient fill, shared by shape/path fills and text
|
|
454
|
+
* backgrounds. When present it overrides the solid `fill` color.
|
|
455
|
+
*
|
|
456
|
+
* `angle` is in degrees: 0 = top→bottom, 90 = left→right, increasing
|
|
457
|
+
* clockwise. Defaults to 0. Rendered as an SVG `<linearGradient>` in
|
|
458
|
+
* objectBoundingBox units so it scales with the layer's box.
|
|
459
|
+
*/
|
|
460
|
+
export interface LinearGradient {
|
|
461
|
+
from: string;
|
|
462
|
+
to: string;
|
|
463
|
+
angle?: number;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/** Border line style, mapped to an SVG stroke-dasharray by the renderer. */
|
|
467
|
+
export type BorderStyle = 'solid' | 'dashed' | 'dotted';
|
|
468
|
+
|
|
225
469
|
/**
|
|
226
470
|
* Shape layer - simple geometric shapes for visual accents.
|
|
227
471
|
*/
|
|
472
|
+
/**
|
|
473
|
+
* Repeating SVG pattern fill for a shape (dots, grid, diagonal lines).
|
|
474
|
+
* Rendered as a native `<pattern>` def — fully vector and export-safe.
|
|
475
|
+
*/
|
|
476
|
+
export interface ShapePattern {
|
|
477
|
+
kind: 'dots' | 'grid' | 'diagonal';
|
|
478
|
+
/** Pattern ink color. */
|
|
479
|
+
color: string;
|
|
480
|
+
/** Tile size in px (default 24). */
|
|
481
|
+
size?: number;
|
|
482
|
+
/** Pattern opacity 0–1 (default 1; tint via a translucent color or this). */
|
|
483
|
+
opacity?: number;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Procedural filter applied to a shape. `noise` renders static film grain
|
|
488
|
+
* via SVG feTurbulence — deliberately not animated so frame capture and
|
|
489
|
+
* the live player agree.
|
|
490
|
+
*/
|
|
491
|
+
export interface ShapeFilter {
|
|
492
|
+
type: 'noise';
|
|
493
|
+
/** feTurbulence base frequency (default 0.8 — fine grain). */
|
|
494
|
+
baseFrequency?: number;
|
|
495
|
+
/** Grain opacity 0–1 (default 0.05). */
|
|
496
|
+
opacity?: number;
|
|
497
|
+
}
|
|
498
|
+
|
|
228
499
|
export interface ShapeLayer extends BaseLayer {
|
|
229
500
|
type: 'shape';
|
|
230
501
|
content: {
|
|
@@ -232,15 +503,88 @@ export interface ShapeLayer extends BaseLayer {
|
|
|
232
503
|
shape: 'rect' | 'circle' | 'line';
|
|
233
504
|
/** Fill color (CSS color or 'none') */
|
|
234
505
|
fill?: string;
|
|
506
|
+
/** Fill opacity 0–1 (applies to solid and gradient fills). */
|
|
507
|
+
fillOpacity?: number;
|
|
508
|
+
/** Gradient fill; overrides `fill` when set. */
|
|
509
|
+
gradient?: LinearGradient;
|
|
510
|
+
/** Repeating pattern fill; overrides `fill`/`gradient` when set. */
|
|
511
|
+
pattern?: ShapePattern;
|
|
512
|
+
/** Procedural filter (film grain). */
|
|
513
|
+
filter?: ShapeFilter;
|
|
235
514
|
/** Stroke color */
|
|
236
515
|
stroke?: string;
|
|
237
516
|
/** Stroke width in pixels */
|
|
238
517
|
strokeWidth?: number;
|
|
518
|
+
/** Border line style (solid/dashed/dotted). Default solid. */
|
|
519
|
+
borderStyle?: BorderStyle;
|
|
239
520
|
/** Corner radius for rect */
|
|
240
521
|
borderRadius?: number;
|
|
241
522
|
};
|
|
242
523
|
}
|
|
243
524
|
|
|
525
|
+
/**
|
|
526
|
+
* End-of-line marker style for a path/connector endpoint.
|
|
527
|
+
* `arrow` is a filled triangle (the classic arrowhead); `open` is a stroked
|
|
528
|
+
* V; `diamond`/`circle`/`square` are filled glyphs; `none` draws nothing.
|
|
529
|
+
*/
|
|
530
|
+
export type MarkerStyle = 'none' | 'arrow' | 'open' | 'diamond' | 'circle' | 'square';
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Path layer - renders an SVG `<path>` for arbitrary curves, connectors,
|
|
534
|
+
* arrows, or filled regions. Used by the diagram template for edges
|
|
535
|
+
* between nodes, the drawing template for non-rect/circle/line shapes, and
|
|
536
|
+
* available to any template that needs a custom geometry.
|
|
537
|
+
*
|
|
538
|
+
* The `position` field carries the layer's bounding box (so animations
|
|
539
|
+
* and clipping work the same as for other layers), but the actual
|
|
540
|
+
* geometry is encoded in the `d` attribute using absolute SVG path
|
|
541
|
+
* coordinates relative to the block viewport.
|
|
542
|
+
*/
|
|
543
|
+
export interface PathLayer extends BaseLayer {
|
|
544
|
+
type: 'path';
|
|
545
|
+
content: {
|
|
546
|
+
/** SVG path `d` attribute (e.g. "M 10 10 L 90 90"). Absolute viewBox coords. */
|
|
547
|
+
d: string;
|
|
548
|
+
/**
|
|
549
|
+
* Named shape kind (e.g. `'diamond'`, `'star'`, `'arrow-right'`) for
|
|
550
|
+
* path layers that represent one of Squisq's standard shapes. When
|
|
551
|
+
* set, the renderer re-derives `d` from the layer's `position` box
|
|
552
|
+
* (resolved against the viewport) instead of using the stored `d` —
|
|
553
|
+
* so the shape moves, resizes, and adapts to any aspect ratio like
|
|
554
|
+
* the native rect/circle/line layers do. Plain paths (connectors,
|
|
555
|
+
* freehand) leave this unset and keep their absolute `d`.
|
|
556
|
+
*/
|
|
557
|
+
shapeKind?: string;
|
|
558
|
+
/** Stroke color (default: theme text color). */
|
|
559
|
+
stroke?: string;
|
|
560
|
+
/** Stroke width in pixels (default: 2). */
|
|
561
|
+
strokeWidth?: number;
|
|
562
|
+
/** Optional fill color (default: 'none' — pure connectors). */
|
|
563
|
+
fill?: string;
|
|
564
|
+
/** Fill opacity 0–1 (applies to solid and gradient fills). */
|
|
565
|
+
fillOpacity?: number;
|
|
566
|
+
/** Gradient fill; overrides `fill` when set. */
|
|
567
|
+
gradient?: LinearGradient;
|
|
568
|
+
/**
|
|
569
|
+
* Border line style (solid/dashed/dotted). A convenience over
|
|
570
|
+
* `dasharray` for named shapes; when set the renderer derives the
|
|
571
|
+
* dash pattern from it (scaled by stroke width).
|
|
572
|
+
*/
|
|
573
|
+
borderStyle?: BorderStyle;
|
|
574
|
+
/** Optional stroke dash pattern (SVG `stroke-dasharray` syntax). */
|
|
575
|
+
dasharray?: string;
|
|
576
|
+
/**
|
|
577
|
+
* Legacy arrowhead flag. Prefer `startMarker`/`endMarker`. When those are
|
|
578
|
+
* unset, `'end'`/`'start'`/`'both'` render a filled-triangle arrowhead.
|
|
579
|
+
*/
|
|
580
|
+
arrow?: 'none' | 'end' | 'start' | 'both';
|
|
581
|
+
/** Marker at the path start (overrides `arrow`). Default: derived from `arrow`. */
|
|
582
|
+
startMarker?: MarkerStyle;
|
|
583
|
+
/** Marker at the path end (overrides `arrow`). Default: derived from `arrow`. */
|
|
584
|
+
endMarker?: MarkerStyle;
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
|
|
244
588
|
/**
|
|
245
589
|
* Map layer - displays a geographic map with optional markers.
|
|
246
590
|
*
|
|
@@ -293,6 +637,16 @@ export interface VideoLayer extends BaseLayer {
|
|
|
293
637
|
clipEnd: number;
|
|
294
638
|
/** Total source video duration (for validation) */
|
|
295
639
|
sourceDuration?: number;
|
|
640
|
+
/**
|
|
641
|
+
* Seconds into the owning block before this video begins playing
|
|
642
|
+
* (the block-relative `startAt`). Default 0 — plays from block start.
|
|
643
|
+
*/
|
|
644
|
+
startAt?: number;
|
|
645
|
+
/**
|
|
646
|
+
* When true, the video keeps playing past the block's end (the
|
|
647
|
+
* playback scheduler re-homes it to the player level). Default false.
|
|
648
|
+
*/
|
|
649
|
+
spillover?: boolean;
|
|
296
650
|
/** Video credit / artist name */
|
|
297
651
|
credit?: string;
|
|
298
652
|
/** License identifier (e.g., 'CC BY-SA 4.0') */
|
|
@@ -399,16 +753,34 @@ export interface TextStyle {
|
|
|
399
753
|
fontFamily?: string;
|
|
400
754
|
/** Font weight */
|
|
401
755
|
fontWeight?: 'normal' | 'bold';
|
|
756
|
+
/** Font style. Also the inherited baseline for rich `content.html`. */
|
|
757
|
+
fontStyle?: 'normal' | 'italic';
|
|
402
758
|
/** Text color (CSS color) */
|
|
403
759
|
color: string;
|
|
404
|
-
/**
|
|
760
|
+
/** Horizontal text alignment within the layer's position box. */
|
|
405
761
|
textAlign?: 'left' | 'center' | 'right';
|
|
762
|
+
/**
|
|
763
|
+
* Vertical alignment of the text within the layer's position box.
|
|
764
|
+
* Requires a `position.height` to have an effect. When omitted, the
|
|
765
|
+
* vertical baseline is derived from `position.anchor` (legacy behavior).
|
|
766
|
+
*/
|
|
767
|
+
verticalAlign?: 'top' | 'middle' | 'bottom';
|
|
406
768
|
/** Line height multiplier */
|
|
407
769
|
lineHeight?: number;
|
|
408
770
|
/** Add drop shadow for readability over images */
|
|
409
771
|
shadow?: boolean;
|
|
410
772
|
/** Background color for text box */
|
|
411
773
|
background?: string;
|
|
774
|
+
/** Background opacity 0–1 (applies to solid and gradient backgrounds). */
|
|
775
|
+
backgroundOpacity?: number;
|
|
776
|
+
/** Gradient background; overrides `background` when set. */
|
|
777
|
+
backgroundGradient?: LinearGradient;
|
|
778
|
+
/** Border (stroke) color for the text box. */
|
|
779
|
+
borderColor?: string;
|
|
780
|
+
/** Border width in pixels. A border renders when > 0 and a color is set. */
|
|
781
|
+
borderWidth?: number;
|
|
782
|
+
/** Border line style (solid/dashed/dotted). Default solid. */
|
|
783
|
+
borderStyle?: BorderStyle;
|
|
412
784
|
/** Padding around text (pixels) */
|
|
413
785
|
padding?: number;
|
|
414
786
|
/** Maximum number of lines before truncation (adds "..." to last line) */
|
|
@@ -451,23 +823,6 @@ export type AnimationType =
|
|
|
451
823
|
| 'panRight'
|
|
452
824
|
| 'typewriter'; // Text appears letter by letter
|
|
453
825
|
|
|
454
|
-
/**
|
|
455
|
-
* Transition between blocks.
|
|
456
|
-
*/
|
|
457
|
-
export interface Transition {
|
|
458
|
-
/** Transition type */
|
|
459
|
-
type: TransitionType;
|
|
460
|
-
/** Duration in seconds */
|
|
461
|
-
duration: number;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
export type TransitionType =
|
|
465
|
-
| 'cut' // Instant switch
|
|
466
|
-
| 'fade' // Cross-fade
|
|
467
|
-
| 'dissolve' // Soft dissolve
|
|
468
|
-
| 'slideLeft' // New block enters from right
|
|
469
|
-
| 'slideRight'; // New block enters from left
|
|
470
|
-
|
|
471
826
|
// ============================================
|
|
472
827
|
// Audio Configuration
|
|
473
828
|
// ============================================
|
|
@@ -525,8 +880,10 @@ export interface CaptionPhrase {
|
|
|
525
880
|
export interface CaptionTrack {
|
|
526
881
|
/** Caption phrases in chronological order */
|
|
527
882
|
phrases: CaptionPhrase[];
|
|
528
|
-
/** When the captions were generated
|
|
529
|
-
|
|
883
|
+
/** When the captions were generated. Optional so that conversion stays
|
|
884
|
+
* deterministic — `markdownToDoc()` only sets it when the caller
|
|
885
|
+
* supplies a timestamp via `captionsGeneratedAt`. */
|
|
886
|
+
generatedAt?: string;
|
|
530
887
|
/** Algorithm version for regeneration detection */
|
|
531
888
|
version: number;
|
|
532
889
|
}
|
|
@@ -630,38 +987,3 @@ export function getCaptionAtTime(
|
|
|
630
987
|
}
|
|
631
988
|
return null;
|
|
632
989
|
}
|
|
633
|
-
|
|
634
|
-
/**
|
|
635
|
-
* Validate a Doc for completeness.
|
|
636
|
-
*/
|
|
637
|
-
export function validateDoc(script: Doc): string[] {
|
|
638
|
-
const errors: string[] = [];
|
|
639
|
-
|
|
640
|
-
if (!script.articleId) {
|
|
641
|
-
errors.push('Missing articleId');
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
if (!script.blocks || script.blocks.length === 0) {
|
|
645
|
-
errors.push('No blocks defined');
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
if (!script.audio || !script.audio.segments || script.audio.segments.length === 0) {
|
|
649
|
-
errors.push('No audio segments defined');
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
// Check for gaps in block coverage
|
|
653
|
-
const totalDuration = script.duration;
|
|
654
|
-
let covered = 0;
|
|
655
|
-
for (const block of script.blocks) {
|
|
656
|
-
if (block.startTime > covered + 0.1) {
|
|
657
|
-
errors.push(`Gap in blocks: ${covered}s to ${block.startTime}s`);
|
|
658
|
-
}
|
|
659
|
-
covered = Math.max(covered, block.startTime + block.duration);
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
if (covered < totalDuration - 0.1) {
|
|
663
|
-
errors.push(`Blocks end at ${covered}s but audio is ${totalDuration}s`);
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
return errors;
|
|
667
|
-
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* bytes in `assets/` and version snapshots in `.versions/`.
|
|
8
8
|
*
|
|
9
9
|
* Layers compose the existing core {@link Layer} types (image / text /
|
|
10
|
-
* shape) so renderers can share infrastructure with the doc system.
|
|
10
|
+
* shape / path) so renderers can share infrastructure with the doc system.
|
|
11
11
|
* Editor-specific metadata (name, visibility, lock, opacity, blendMode)
|
|
12
12
|
* lives in {@link EditorLayerMeta} and is merged onto each layer. The
|
|
13
13
|
* {@link Layer.animation} field is permitted but ignored by the image
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* relative to the sidecar root, keeping the document portable.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import type { ImageLayer, ShapeLayer, TextLayer } from './Doc.js';
|
|
20
|
+
import type { ImageLayer, PathLayer, ShapeLayer, TextLayer } from './Doc.js';
|
|
21
21
|
|
|
22
22
|
// ============================================
|
|
23
23
|
// Layer type
|
|
@@ -44,8 +44,15 @@ export interface EditorLayerMeta {
|
|
|
44
44
|
blendMode?: GlobalCompositeOperation;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
/**
|
|
48
|
-
|
|
47
|
+
/**
|
|
48
|
+
* A layer in an {@link ImageEditDoc}.
|
|
49
|
+
*
|
|
50
|
+
* `path` layers carry the full drawing-shape vocabulary: when
|
|
51
|
+
* `content.shapeKind` is set (e.g. `'diamond'`, `'star'`, `'arrow-right'`),
|
|
52
|
+
* the renderer re-derives the SVG `d` from the layer's `position` box via
|
|
53
|
+
* `shapePath`, so the shape moves/resizes like the native rect/circle/line.
|
|
54
|
+
*/
|
|
55
|
+
export type ImageEditLayer = (ImageLayer | TextLayer | ShapeLayer | PathLayer) & EditorLayerMeta;
|
|
49
56
|
|
|
50
57
|
/** The layer kinds the image editor supports. */
|
|
51
58
|
export type ImageEditLayerKind = ImageEditLayer['type'];
|