@bendyline/squisq 2.11.7 → 2.11.9

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 (40) hide show
  1. package/dist/{Doc-BkxT7G80.d.ts → Doc-DmElSKmg.d.ts} +219 -1
  2. package/dist/{ImageEditDoc-C8ZB54Vv.d.ts → ImageEditDoc-Dm_BETxC.d.ts} +1 -1
  3. package/dist/{chunk-EF353KGH.js → chunk-2PGC4JDT.js} +1 -1
  4. package/dist/{chunk-YGGYYBJS.js → chunk-B5STNW6C.js} +2 -2
  5. package/dist/{chunk-IYZTF4VO.js → chunk-CCRBHFNO.js} +3 -3
  6. package/dist/{chunk-VU4T74LI.js → chunk-DTM4FG7S.js} +1 -1
  7. package/dist/chunk-JSGIWW35.js +70 -0
  8. package/dist/chunk-L7QZORLB.js +230 -0
  9. package/dist/chunk-NEWNNLWN.js +64 -0
  10. package/dist/{chunk-6ECMNUIP.js → chunk-OU5FYBOB.js} +170 -4
  11. package/dist/{chunk-Y4D6TDZT.js → chunk-PCCQLD3G.js} +2 -0
  12. package/dist/{chunk-SKKBRLLM.js → chunk-QDA7NXDO.js} +7 -42
  13. package/dist/{chunk-3YNFMFNK.js → chunk-QOVINAB2.js} +18 -9
  14. package/dist/{chunk-SOIV7KDO.js → chunk-VRTXPGP7.js} +256 -26
  15. package/dist/{chunk-XJXBI3N5.js → chunk-XZVBR5BP.js} +1 -1
  16. package/dist/{chunk-GAZKTT4R.js → chunk-YNO6JV36.js} +96 -33
  17. package/dist/doc/index.d.ts +10 -6
  18. package/dist/doc/index.js +23 -21
  19. package/dist/fence/index.d.ts +1 -1
  20. package/dist/generate/index.d.ts +1 -1
  21. package/dist/imageEdit/index.d.ts +47 -4
  22. package/dist/imageEdit/index.js +5 -1
  23. package/dist/index.d.ts +5 -5
  24. package/dist/index.js +52 -41
  25. package/dist/jsonForm/index.d.ts +1 -1
  26. package/dist/jsonForm/index.js +6 -4
  27. package/dist/markdown/index.js +3 -3
  28. package/dist/{materializePageSection-Dp2aHFbc.d.ts → materializePageSection-BfttC9Zj.d.ts} +6 -3
  29. package/dist/mediaEdit/index.d.ts +467 -0
  30. package/dist/mediaEdit/index.js +990 -0
  31. package/dist/narration/index.d.ts +20 -12
  32. package/dist/narration/index.js +7 -5
  33. package/dist/schemas/index.d.ts +4 -4
  34. package/dist/schemas/index.js +10 -4
  35. package/dist/{themeLibrary-BbSjnGmd.d.ts → themeLibrary-ChnTImby.d.ts} +1 -1
  36. package/dist/timing/index.d.ts +1 -1
  37. package/dist/transform/index.d.ts +2 -2
  38. package/dist/transform/index.js +7 -6
  39. package/package.json +6 -1
  40. package/dist/{chunk-CW24CH7I.js → chunk-HUXK7EOT.js} +3 -3
@@ -1,5 +1,158 @@
1
1
  import { a3 as Transition, a5 as TransitionType, M as MarkdownBlockNode, r as MarkdownHeading } from './types-Be6sBUBx.js';
2
2
 
3
+ /**
4
+ * Media-edit recipes — the non-destructive edit list a media reference carries.
5
+ *
6
+ * A recipe lives in the markdown, as parameters on the `{[audio|video …]}`
7
+ * annotation or `data-squisq-{audio|video}-*` attributes on a standalone
8
+ * `<audio>` / `<video>` tag. The source file is never modified: timeline ops
9
+ * (`cuts`, `gain`, `fadeIn`, `fadeOut`, `crop`) are applied at playback and
10
+ * export, and the signal chain (`fx`) is rendered into a derived, time-aligned
11
+ * audio file (see `renderStore.ts`). Undo is therefore the editor's ordinary
12
+ * undo, and a reference with no recipe behaves exactly as before.
13
+ *
14
+ * Pure and dependency-free: runs in the browser and in Node.
15
+ */
16
+ /** Signal operations, in the FIXED order the chain applies them. */
17
+ declare const MEDIA_FX_ORDER: readonly ["highpass", "denoise", "debreath", "loudness"];
18
+ type MediaFxOpId = (typeof MEDIA_FX_ORDER)[number];
19
+ interface MediaFxOpSpec {
20
+ /** Value used when the token carries none (`denoise` ≡ `denoise:0.8`). */
21
+ defaultValue: number;
22
+ min: number;
23
+ max: number;
24
+ }
25
+ /**
26
+ * Parameter contract per op. Values are clamped into range on parse, so a
27
+ * recipe always describes something the engine can render.
28
+ *
29
+ * - `highpass` — corner frequency in Hz.
30
+ * - `denoise` — wet/dry strength, 0…1.
31
+ * - `debreath` — attenuation applied to detected breaths, in dB (≤ 0).
32
+ * - `loudness` — integrated loudness target in LUFS.
33
+ */
34
+ declare const MEDIA_FX_SPECS: Readonly<Record<MediaFxOpId, MediaFxOpSpec>>;
35
+ interface MediaFxOp {
36
+ id: MediaFxOpId;
37
+ value: number;
38
+ }
39
+ interface MediaFxChain {
40
+ /** Known ops, de-duplicated (last wins) and in {@link MEDIA_FX_ORDER}. */
41
+ ops: MediaFxOp[];
42
+ /**
43
+ * Tokens this engine does not understand, preserved verbatim so a recipe
44
+ * written by a newer engine survives a round-trip through an older one.
45
+ * They are never rendered.
46
+ */
47
+ unknown: string[];
48
+ }
49
+ /** A removed range of the SOURCE file, in seconds (`start < end`). */
50
+ interface MediaCut {
51
+ start: number;
52
+ end: number;
53
+ }
54
+ /** A crop rectangle, normalized to the source frame (0…1 on each axis). */
55
+ interface MediaCrop {
56
+ x: number;
57
+ y: number;
58
+ w: number;
59
+ h: number;
60
+ }
61
+ /** The complete recipe a media reference can carry. Every field is optional. */
62
+ interface MediaEdits {
63
+ fx?: MediaFxChain;
64
+ /** Normalized: sorted, merged, non-overlapping. */
65
+ cuts?: MediaCut[];
66
+ /** Clip gain in dB. */
67
+ gain?: number;
68
+ /** Fade-in length in seconds, at the start of the played clip. */
69
+ fadeIn?: number;
70
+ /** Fade-out length in seconds, at the end of the played clip. */
71
+ fadeOut?: number;
72
+ crop?: MediaCrop;
73
+ /**
74
+ * Links companion clips (a screen + camera capture, a narration audio +
75
+ * video pair). Editors propagate cuts, trims and `fx` across a group.
76
+ */
77
+ group?: string;
78
+ }
79
+ /** Raw string values of a recipe, keyed by {@link MediaEditParamKey}. */
80
+ type MediaEditParamValues = Partial<Record<MediaEditParamKey, string>>;
81
+ type MediaEditParamKey = 'fx' | 'cuts' | 'gain' | 'fadeIn' | 'fadeOut' | 'crop' | 'group';
82
+ /**
83
+ * Every recipe parameter with its two spellings: the annotation key
84
+ * (`fadeIn=0.3`) and the HTML attribute suffix, appended to the per-kind
85
+ * prefix (`data-squisq-video-fade-in="0.3"`). The order is the canonical
86
+ * serialization order.
87
+ */
88
+ declare const MEDIA_EDIT_PARAMS: ReadonlyArray<{
89
+ key: MediaEditParamKey;
90
+ htmlSuffix: string;
91
+ }>;
92
+ /** `data-squisq-video-fade-in` for (`video`, `fadeIn`). */
93
+ declare function mediaEditHtmlAttribute(kind: 'audio' | 'video', key: MediaEditParamKey): string;
94
+ /** Compact, stable decimal: at most `digits` fraction digits, no `-0`. */
95
+ declare function formatMediaNumber(value: number, digits?: number): string;
96
+ /**
97
+ * Parse an `fx` value (`"highpass:80 denoise debreath:-15"`). Tokens split on
98
+ * whitespace or commas. A known op with a missing value gets its default; a
99
+ * known op with an unparseable value is kept verbatim in `unknown` rather
100
+ * than guessed at. `debreath:15` is read as −15 dB (attenuation is the only
101
+ * meaningful direction). Returns null when the value holds no tokens.
102
+ */
103
+ declare function parseMediaFx(raw: string | undefined): MediaFxChain | null;
104
+ /**
105
+ * Canonical `fx` string: known ops in chain order with explicit values, then
106
+ * unknown tokens in their authored order. Explicit values keep a recipe's
107
+ * meaning stable even if a later engine changes a default.
108
+ */
109
+ declare function serializeMediaFx(chain: MediaFxChain): string;
110
+ /** True when the chain would render anything (it has at least one known op). */
111
+ declare function hasRenderableFx(chain: MediaFxChain | undefined): chain is MediaFxChain;
112
+ /**
113
+ * Sort, merge overlapping or touching ranges, and drop empty ones. When a
114
+ * `[windowStart, windowEnd]` source window is given (the clip's trim), cuts
115
+ * are clamped into it and anything outside is dropped.
116
+ */
117
+ declare function normalizeMediaCuts(cuts: readonly MediaCut[], windowStart?: number, windowEnd?: number): MediaCut[];
118
+ /**
119
+ * Parse `"12.4-13.1 40.2-41"` (also `1:02-1:04.5`, comma separated). Invalid
120
+ * ranges are dropped. Returns null when nothing valid remains.
121
+ */
122
+ declare function parseMediaCuts(raw: string | undefined): MediaCut[] | null;
123
+ declare function serializeMediaCuts(cuts: readonly MediaCut[]): string;
124
+ /**
125
+ * Parse `"x y w h"` (fractions of the source frame). The rectangle is clamped
126
+ * inside the frame. A full-frame rectangle means "no crop" and returns null.
127
+ */
128
+ declare function parseMediaCrop(raw: string | undefined): MediaCrop | null;
129
+ /** Clamp a crop rectangle into the frame; null when it covers the whole frame. */
130
+ declare function normalizeMediaCrop(crop: MediaCrop): MediaCrop | null;
131
+ declare function serializeMediaCrop(crop: MediaCrop): string;
132
+ /**
133
+ * Parse a recipe from raw parameter values. Invalid fields are dropped
134
+ * (never guessed); neutral values (`gain=0`, `fadeIn=0`, full-frame crop)
135
+ * are dropped too. Returns undefined when nothing remains, so callers can
136
+ * leave `MediaClip.edits` unset for an unedited reference.
137
+ */
138
+ declare function parseMediaEdits(values: MediaEditParamValues): MediaEdits | undefined;
139
+ /**
140
+ * Serialize a recipe to raw parameter values. A key maps to `null` when its
141
+ * field is absent, so a writer can remove a stale attribute with the same
142
+ * call that sets the others.
143
+ */
144
+ declare function serializeMediaEdits(edits: MediaEdits | undefined): Record<MediaEditParamKey, string | null>;
145
+ /** Read recipe values from annotation params (`fx=…`, `fadeIn=…`). */
146
+ declare function mediaEditValuesFromParams(params: Record<string, string>): MediaEditParamValues;
147
+ /** Read recipe values from HTML attributes (`data-squisq-video-fade-in=…`). */
148
+ declare function mediaEditValuesFromAttributes(kind: 'audio' | 'video', attributes: Record<string, string>): MediaEditParamValues;
149
+ /**
150
+ * Stable key naming the render of `src` under `fx`. Only the known, canonical
151
+ * ops take part — unknown tokens are not rendered, so they must not force a
152
+ * re-render (the render manifest records them instead). 12 hex digits.
153
+ */
154
+ declare function mediaRenderKey(src: string, fx: MediaFxChain): string;
155
+
3
156
  /**
4
157
  * Media-clip timing model.
5
158
  *
@@ -76,6 +229,11 @@ interface MediaClip {
76
229
  * timed relative to the document start and able to span every block.
77
230
  */
78
231
  anchor: 'block' | 'document';
232
+ /**
233
+ * Non-destructive edit recipe (`fx`, `cuts`, `gain`, fades, `crop`,
234
+ * `group`). Absent for an unedited reference. See `@bendyline/squisq/mediaEdit`.
235
+ */
236
+ edits?: MediaEdits;
79
237
  /**
80
238
  * 1-based source line of the authoring annotation, when derived from
81
239
  * markdown. Enables round-tripping edits (e.g. the timeline editor rewriting
@@ -128,6 +286,36 @@ interface ScheduledClip {
128
286
  blockId?: string;
129
287
  /** 1-based source line of the authoring annotation, when known. */
130
288
  sourceLine?: number;
289
+ /** Clip gain in dB (from the recipe). */
290
+ gain?: number;
291
+ /** Fade-in seconds at this entry's start (first segment of a cut clip only). */
292
+ fadeIn?: number;
293
+ /** Fade-out seconds at this entry's end (last segment of a cut clip only). */
294
+ fadeOut?: number;
295
+ /** Normalized crop rectangle for a video clip. */
296
+ crop?: MediaCrop;
297
+ /**
298
+ * True when a video's own audio track must stay silent because a processed
299
+ * companion audio entry (see {@link ScheduledClip.derivedFrom}) plays in its place.
300
+ */
301
+ audioMuted?: boolean;
302
+ /**
303
+ * Set on the processed companion audio entry emitted for an edited video:
304
+ * the id of the clip whose audio it replaces. Timeline UIs hide these.
305
+ */
306
+ derivedFrom?: string;
307
+ /** The source reference before processed-audio substitution. */
308
+ originalSrc?: string;
309
+ /**
310
+ * Present when a clip with cuts was expanded into contiguous entries, one
311
+ * per kept source range. `groupId` is the authored clip's id; entries of
312
+ * one group play the same source back to back.
313
+ */
314
+ segment?: {
315
+ groupId: string;
316
+ index: number;
317
+ count: number;
318
+ };
131
319
  }
132
320
  /** Options for {@link resolveMediaSchedule} / {@link getDocPlaybackDuration}. */
133
321
  interface MediaScheduleOptions {
@@ -146,7 +334,26 @@ interface MediaScheduleOptions {
146
334
  * block by design.
147
335
  */
148
336
  intrinsicDuration?: (clip: MediaClip) => number | undefined;
337
+ /**
338
+ * Optional lookup of a clip's processed (rendered `fx`) audio. When it
339
+ * returns a path, an audio clip plays that path instead of its source, and a
340
+ * video clip keeps its picture but mutes its own audio while a companion
341
+ * audio entry plays the processed track with identical timing. Renders are
342
+ * sample-aligned with the source, so no timing changes.
343
+ *
344
+ * Return undefined when no current render exists (the default when no
345
+ * lookup is wired): the clip then plays its original audio.
346
+ */
347
+ processedAudio?: (clip: MediaClip) => string | undefined;
149
348
  }
349
+ /**
350
+ * Schedule one clip that occupies `[start, end)` on the doc timeline, honoring
351
+ * its recipe (cuts → contiguous segment entries, gain/fades/crop, processed
352
+ * audio). {@link resolveMediaSchedule} uses this for every annotated clip;
353
+ * hosts that schedule media from other sources (body-embedded `<audio>` /
354
+ * `<video>` tags) call it so edits behave identically there.
355
+ */
356
+ declare function scheduleMediaClip(clip: MediaClip, start: number, end: number, anchor: 'block' | 'document', blockId?: string, opts?: MediaScheduleOptions): ScheduledClip[];
150
357
  /**
151
358
  * Flatten every block clip and document clip into absolute-timed
152
359
  * `ScheduledClip`s. Pure — depends only on `doc` (plus the optional intrinsic
@@ -1374,6 +1581,17 @@ interface ProgressIndicatorConfig {
1374
1581
  */
1375
1582
  declare const PAGE_SECTION_KINDS: readonly ["hero", "banner", "stat-band", "quote-band", "feature-split", "media-figure", "gallery", "callout", "card-grid", "item-list", "timeline-rail", "table-section", "canvas-embed", "prose", "footer"];
1376
1583
  type PageSectionKind = (typeof PAGE_SECTION_KINDS)[number];
1584
+ /**
1585
+ * How a page rendition reads. `page` (the default) is the art-directed
1586
+ * scrolling site: a centered cover hero, display type, section bands, and
1587
+ * content-aware templates. `document` is the working-document register for
1588
+ * reports, notes, and previews: a left-aligned masthead, one heading scale
1589
+ * that follows the markdown hierarchy whatever section carries it, one flat
1590
+ * surface, and markdown structure kept as written — auto-picked templates
1591
+ * render as prose, while authored `{[template]}` annotations still apply.
1592
+ */
1593
+ declare const PAGE_VARIANTS: readonly ["page", "document"];
1594
+ type PageVariant = (typeof PAGE_VARIANTS)[number];
1377
1595
  /** Relative visual weight of a section within the page. */
1378
1596
  type PageEmphasis = 'lead' | 'strong' | 'standard' | 'quiet';
1379
1597
  /** Which background treatment a section sits on. */
@@ -2847,4 +3065,4 @@ declare function getBlockAtTime(blocks: Block[], time: number): Block | null;
2847
3065
  */
2848
3066
  declare function getCaptionAtTime(captions: CaptionTrack | undefined, time: number): CaptionPhrase | null;
2849
3067
 
2850
- export { type ImageLayer as $, type AccentImage as A, type BarChartInput as B, type CaptionPhrase as C, DARK_SURFACE as D, DEFAULT_DOC_FONT as E, DEFAULT_TITLE_FONT as F, type DataTableInput as G, type DateEventInput as H, type DeepPartial as I, type DefinitionCardInput as J, type DiagramBlockInput as K, type DiagramEdgeAnchor as L, type DiagramTemplateEdge as M, type DiagramTemplateNode as N, type Doc as O, type DocBlock as P, type DocDiagnostic as Q, type DonutChartInput as R, type DrawingBlockInput as S, FRONTMATTER_CUSTOM_TEMPLATES_KEY as T, FRONTMATTER_CUSTOM_THEMES_KEY as U, type FactCardInput as V, type FontFamily as W, type FontFamilyKind as X, type FullBleedQuoteInput as Y, type GradientBackgroundConfig as Z, type ImageBackgroundConfig as _, type AccentPosition as a, type ScheduledClip as a$, type ImageTreatment as a0, type ImageWithCaptionInput as a1, LIGHT_SURFACE as a2, type Layer as a3, type LayerRepeat as a4, type LayoutHints as a5, type LeftFeatureInput as a6, type LineChartInput as a7, type LinearGradient as a8, type ListBlockInput as a9, type PageAccentRotation as aA, type PageBackground as aB, type PageDesignFamily as aC, type PageEmphasis as aD, type PageHeadingTreatment as aE, type PageSectionKind as aF, type PageSectionOverride as aG, type PageTokens as aH, type PathLayer as aI, type PatternBackgroundConfig as aJ, type PersistentLayer as aK, type PersistentLayerConfig as aL, type PersistentLayerTemplate as aM, type PersistentLayerTemplateConfig as aN, type PersistentLayerTemplateType as aO, type PhotoGridInput as aP, type PieChartInput as aQ, type PipStyle as aR, type Position as aS, type ProgressIndicatorConfig as aT, type PromotedBodyAnnotation as aU, type PullQuoteInput as aV, type QuoteBlockInput as aW, type RawLayersInput as aX, type RenderStyle as aY, type RightFeatureInput as aZ, type ScatterChartInput as a_, type MapBlockInput as aa, type MapLayer as ab, type MapMarker as ac, type MapTileStyle as ad, type MarkerStyle as ae, type MediaClip as af, type MediaScheduleOptions as ag, type MermaidLayer as ah, PAGE_ACCENT_STRATEGIES as ai, PAGE_BACKGROUNDS as aj, PAGE_BACKGROUND_RHYTHMS as ak, PAGE_DESIGN_FAMILIES as al, PAGE_DIVIDERS as am, PAGE_EMPHASES as an, PAGE_EYEBROWS as ao, PAGE_HEADING_CASES as ap, PAGE_HEADING_SCALES as aq, PAGE_HEADING_UNDERLINES as ar, PAGE_HERO_STYLES as as, PAGE_IMAGE_FRAMINGS as at, PAGE_NUMERAL_STYLES as au, PAGE_PATTERNS as av, PAGE_QUOTE_MARKS as aw, PAGE_SECTION_KINDS as ax, PAGE_SECTION_SPACINGS as ay, PAGE_SHADOWS as az, type AmbientGradientConfig as b, getSafeTextBounds as b$, type SectionHeaderInput as b0, type ShapeFilter as b1, type ShapeLayer as b2, type ShapePattern as b3, type SolidBackgroundConfig as b4, type StartBlockConfig as b5, type StatHighlightInput as b6, type SurfaceScheme as b7, THEME_SCHEMA_VERSION as b8, type TableLayer as b9, type TreeLayerStyle as bA, type TreeTemplateItem as bB, type TwoColumnInput as bC, VIEWPORT_PRESETS as bD, type VideoLayer as bE, type VideoPipPosition as bF, type VideoPipShape as bG, type VideoPipSize as bH, type VideoPlacement as bI, type VideoPresentation as bJ, type VideoPullQuoteInput as bK, type VideoWithCaptionInput as bL, type ViewportConfig as bM, type ViewportOrientation as bN, type ViewportPreset as bO, type VignetteConfig as bP, applySurface as bQ, calculateDuration as bR, calculateFontScale as bS, createTemplateContext as bT, createTheme as bU, createThemeRegistry as bV, getAspectRatioString as bW, getBlockAtTime as bX, getCaptionAtTime as bY, getDocPlaybackDuration as bZ, getLayoutHints as b_, type TableLayerStyle as ba, type TemplateBlock as bb, type TemplateContext as bc, type TemplateFunction as bd, type TemplateRegistry as be, type TextLayer as bf, type TextStyle as bg, type Theme as bh, type ThemeColorPalette as bi, type ThemeColorScheme as bj, type ThemePageStyle as bk, type ThemeRegistry as bl, type ThemeSchemaVersion as bm, type ThemeSeedColors as bn, type ThemeStyle as bo, type ThemeTypography as bp, type TimelineBlockInput as bq, type TimelineTemplateEvent as br, type TimelineTemplateLink as bs, type TimelineTemplateTrack as bt, type TitleBlockInput as bu, type TitleCaptionConfig as bv, type TranscriptBlockInput as bw, type TreeBlockInput as bx, type TreeLayer as by, type TreeLayerItem as bz, type Animation as c, getSegmentAtTime as c0, getTwoColumnPositions as c1, getViewport as c2, getViewportOrientation as c3, isCustomTemplateDefinition as c4, isPersistentLayerTemplate as c5, isTemplateBlock as c6, scaledFontSize$1 as c7, resolveMediaSchedule as c8, scaledFontSize as c9, validateCustomTemplateDefinition as ca, type AnimationType as d, type AreaChartInput as e, type AudioBookmark as f, type AudioSegment as g, type AudioTimingData as h, type AudioTrack as i, type BigTextInput as j, type Block as k, type BlockConnection as l, type BorderStyle as m, type CaptionTrack as n, type CaptionWord as o, type ChartBaseFields as p, type ChartTemplateInput as q, type ColorScheme as r, type ColumnChartInput as s, type ComparisonBarInput as t, type ContentBlockInput as u, type CornerBrandingConfig as v, type CustomTemplateDefinition as w, type CustomTemplateLayer as x, type CustomTemplateValidationError as y, type CustomTemplateValidationResult as z };
3068
+ export { type ImageLayer as $, type AccentImage as A, type BarChartInput as B, type CaptionPhrase as C, DARK_SURFACE as D, DEFAULT_DOC_FONT as E, DEFAULT_TITLE_FONT as F, type DataTableInput as G, type DateEventInput as H, type DeepPartial as I, type DefinitionCardInput as J, type DiagramBlockInput as K, type DiagramEdgeAnchor as L, type DiagramTemplateEdge as M, type DiagramTemplateNode as N, type Doc as O, type DocBlock as P, type DocDiagnostic as Q, type DonutChartInput as R, type DrawingBlockInput as S, FRONTMATTER_CUSTOM_TEMPLATES_KEY as T, FRONTMATTER_CUSTOM_THEMES_KEY as U, type FactCardInput as V, type FontFamily as W, type FontFamilyKind as X, type FullBleedQuoteInput as Y, type GradientBackgroundConfig as Z, type ImageBackgroundConfig as _, type AccentPosition as a, type QuoteBlockInput as a$, type ImageTreatment as a0, type ImageWithCaptionInput as a1, LIGHT_SURFACE as a2, type Layer as a3, type LayerRepeat as a4, type LayoutHints as a5, type LeftFeatureInput as a6, type LineChartInput as a7, type LinearGradient as a8, type ListBlockInput as a9, PAGE_SECTION_KINDS as aA, PAGE_SECTION_SPACINGS as aB, PAGE_SHADOWS as aC, PAGE_VARIANTS as aD, type PageAccentRotation as aE, type PageBackground as aF, type PageDesignFamily as aG, type PageEmphasis as aH, type PageHeadingTreatment as aI, type PageSectionKind as aJ, type PageSectionOverride as aK, type PageTokens as aL, type PageVariant as aM, type PathLayer as aN, type PatternBackgroundConfig as aO, type PersistentLayer as aP, type PersistentLayerConfig as aQ, type PersistentLayerTemplate as aR, type PersistentLayerTemplateConfig as aS, type PersistentLayerTemplateType as aT, type PhotoGridInput as aU, type PieChartInput as aV, type PipStyle as aW, type Position as aX, type ProgressIndicatorConfig as aY, type PromotedBodyAnnotation as aZ, type PullQuoteInput as a_, type MapBlockInput as aa, type MapLayer as ab, type MapMarker as ac, type MapTileStyle as ad, type MarkerStyle as ae, type MediaClip as af, type MediaCrop as ag, type MediaCut as ah, type MediaEdits as ai, type MediaScheduleOptions as aj, type MermaidLayer as ak, PAGE_ACCENT_STRATEGIES as al, PAGE_BACKGROUNDS as am, PAGE_BACKGROUND_RHYTHMS as an, PAGE_DESIGN_FAMILIES as ao, PAGE_DIVIDERS as ap, PAGE_EMPHASES as aq, PAGE_EYEBROWS as ar, PAGE_HEADING_CASES as as, PAGE_HEADING_SCALES as at, PAGE_HEADING_UNDERLINES as au, PAGE_HERO_STYLES as av, PAGE_IMAGE_FRAMINGS as aw, PAGE_NUMERAL_STYLES as ax, PAGE_PATTERNS as ay, PAGE_QUOTE_MARKS as az, type AmbientGradientConfig as b, getAspectRatioString as b$, type RawLayersInput as b0, type RenderStyle as b1, type RightFeatureInput as b2, type ScatterChartInput as b3, type ScheduledClip as b4, type SectionHeaderInput as b5, type ShapeFilter as b6, type ShapeLayer as b7, type ShapePattern as b8, type SolidBackgroundConfig as b9, type TitleCaptionConfig as bA, type TranscriptBlockInput as bB, type TreeBlockInput as bC, type TreeLayer as bD, type TreeLayerItem as bE, type TreeLayerStyle as bF, type TreeTemplateItem as bG, type TwoColumnInput as bH, VIEWPORT_PRESETS as bI, type VideoLayer as bJ, type VideoPipPosition as bK, type VideoPipShape as bL, type VideoPipSize as bM, type VideoPlacement as bN, type VideoPresentation as bO, type VideoPullQuoteInput as bP, type VideoWithCaptionInput as bQ, type ViewportConfig as bR, type ViewportOrientation as bS, type ViewportPreset as bT, type VignetteConfig as bU, applySurface as bV, calculateDuration as bW, calculateFontScale as bX, createTemplateContext as bY, createTheme as bZ, createThemeRegistry as b_, type StartBlockConfig as ba, type StatHighlightInput as bb, type SurfaceScheme as bc, THEME_SCHEMA_VERSION as bd, type TableLayer as be, type TableLayerStyle as bf, type TemplateBlock as bg, type TemplateContext as bh, type TemplateFunction as bi, type TemplateRegistry as bj, type TextLayer as bk, type TextStyle as bl, type Theme as bm, type ThemeColorPalette as bn, type ThemeColorScheme as bo, type ThemePageStyle as bp, type ThemeRegistry as bq, type ThemeSchemaVersion as br, type ThemeSeedColors as bs, type ThemeStyle as bt, type ThemeTypography as bu, type TimelineBlockInput as bv, type TimelineTemplateEvent as bw, type TimelineTemplateLink as bx, type TimelineTemplateTrack as by, type TitleBlockInput as bz, type Animation as c, getBlockAtTime as c0, getCaptionAtTime as c1, getDocPlaybackDuration as c2, getLayoutHints as c3, getSafeTextBounds as c4, getSegmentAtTime as c5, getTwoColumnPositions as c6, getViewport as c7, getViewportOrientation as c8, isCustomTemplateDefinition as c9, parseMediaFx as cA, serializeMediaCrop as cB, serializeMediaCuts as cC, serializeMediaEdits as cD, serializeMediaFx as cE, isPersistentLayerTemplate as ca, isTemplateBlock as cb, scaledFontSize$1 as cc, resolveMediaSchedule as cd, scaledFontSize as ce, scheduleMediaClip as cf, validateCustomTemplateDefinition as cg, type MediaFxOpId as ch, type MediaFxChain as ci, MEDIA_EDIT_PARAMS as cj, MEDIA_FX_ORDER as ck, MEDIA_FX_SPECS as cl, type MediaEditParamKey as cm, type MediaEditParamValues as cn, type MediaFxOp as co, formatMediaNumber as cp, hasRenderableFx as cq, mediaEditHtmlAttribute as cr, mediaEditValuesFromAttributes as cs, mediaEditValuesFromParams as ct, mediaRenderKey as cu, normalizeMediaCrop as cv, normalizeMediaCuts as cw, parseMediaCrop as cx, parseMediaCuts as cy, parseMediaEdits as cz, type AnimationType as d, type AreaChartInput as e, type AudioBookmark as f, type AudioSegment as g, type AudioTimingData as h, type AudioTrack as i, type BigTextInput as j, type Block as k, type BlockConnection as l, type BorderStyle as m, type CaptionTrack as n, type CaptionWord as o, type ChartBaseFields as p, type ChartTemplateInput as q, type ColorScheme as r, type ColumnChartInput as s, type ComparisonBarInput as t, type ContentBlockInput as u, type CornerBrandingConfig as v, type CustomTemplateDefinition as w, type CustomTemplateLayer as x, type CustomTemplateValidationError as y, type CustomTemplateValidationResult as z };
@@ -1,4 +1,4 @@
1
- import { $ as ImageLayer, bf as TextLayer, b2 as ShapeLayer, aI as PathLayer } from './Doc-BkxT7G80.js';
1
+ import { $ as ImageLayer, bk as TextLayer, b7 as ShapeLayer, aN as PathLayer } from './Doc-DmElSKmg.js';
2
2
 
3
3
  /**
4
4
  * ImageEditDoc — JSON document describing a layered, editable image.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  flattenRenderableBlocks,
3
3
  getBlockBodyText
4
- } from "./chunk-3YNFMFNK.js";
4
+ } from "./chunk-QOVINAB2.js";
5
5
  import {
6
6
  estimateSpokenWordCount
7
7
  } from "./chunk-GHOPHGOK.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  defaultPageStyle
3
- } from "./chunk-GAZKTT4R.js";
3
+ } from "./chunk-YNO6JV36.js";
4
4
  import {
5
5
  FONT_FALLBACKS,
6
6
  THEME_SCHEMA_VERSION,
@@ -15,7 +15,7 @@ import {
15
15
  relativeLuminance,
16
16
  resolveFontFamily,
17
17
  withAlpha
18
- } from "./chunk-Y4D6TDZT.js";
18
+ } from "./chunk-PCCQLD3G.js";
19
19
 
20
20
  // src/schemas/Doc.ts
21
21
  function calculateDuration(audio) {
@@ -5,14 +5,14 @@ import {
5
5
  } from "./chunk-SVN7T6BK.js";
6
6
  import {
7
7
  markdownToDoc
8
- } from "./chunk-3YNFMFNK.js";
8
+ } from "./chunk-QOVINAB2.js";
9
9
  import {
10
10
  cloneAndFreezeData,
11
11
  isTemplateBlock
12
- } from "./chunk-Y4D6TDZT.js";
12
+ } from "./chunk-PCCQLD3G.js";
13
13
  import {
14
14
  parseMarkdown
15
- } from "./chunk-CW24CH7I.js";
15
+ } from "./chunk-HUXK7EOT.js";
16
16
  import {
17
17
  extractPlainText,
18
18
  getChildren
@@ -2,7 +2,7 @@ import {
2
2
  DEFAULT_THEME,
3
3
  applySurface,
4
4
  resolveFontFamily
5
- } from "./chunk-Y4D6TDZT.js";
5
+ } from "./chunk-PCCQLD3G.js";
6
6
 
7
7
  // src/jsonForm/chooseControl.ts
8
8
  var ENUM_SEGMENTED_LIMIT = 4;
@@ -0,0 +1,70 @@
1
+ import {
2
+ normalizeMediaCuts
3
+ } from "./chunk-L7QZORLB.js";
4
+
5
+ // src/mediaEdit/timeMap.ts
6
+ function createMediaTimeMap(input) {
7
+ const windowStart = Math.max(0, input.clipStart ?? 0);
8
+ let windowEnd = input.clipEnd ?? Number.POSITIVE_INFINITY;
9
+ if (input.sourceDuration != null && Number.isFinite(input.sourceDuration)) {
10
+ windowEnd = Math.min(windowEnd, input.sourceDuration);
11
+ }
12
+ windowEnd = Math.max(windowStart, windowEnd);
13
+ const cuts = normalizeMediaCuts(input.cuts ?? [], windowStart, windowEnd);
14
+ const kept = [];
15
+ let cursor = windowStart;
16
+ for (const cut of cuts) {
17
+ if (cut.start > cursor) kept.push({ start: cursor, end: cut.start });
18
+ cursor = Math.max(cursor, cut.end);
19
+ }
20
+ if (windowEnd > cursor) kept.push({ start: cursor, end: windowEnd });
21
+ const offsets = [];
22
+ let total = 0;
23
+ for (const range of kept) {
24
+ offsets.push(total);
25
+ total += range.end - range.start;
26
+ }
27
+ const playedDuration = total;
28
+ const sourceToPlayed = (t) => {
29
+ for (let i = 0; i < kept.length; i++) {
30
+ const range = kept[i];
31
+ if (t >= range.start && (t < range.end || i === kept.length - 1 && t === range.end)) {
32
+ return offsets[i] + (t - range.start);
33
+ }
34
+ }
35
+ return null;
36
+ };
37
+ const snapSourceToPlayed = (t) => {
38
+ if (kept.length === 0 || t <= windowStart) return 0;
39
+ for (let i = 0; i < kept.length; i++) {
40
+ const range = kept[i];
41
+ if (t < range.start) return offsets[i];
42
+ if (t < range.end) return offsets[i] + (t - range.start);
43
+ }
44
+ return playedDuration;
45
+ };
46
+ const playedToSource = (p) => {
47
+ if (kept.length === 0) return windowStart;
48
+ if (p <= 0) return kept[0].start;
49
+ for (let i = 0; i < kept.length; i++) {
50
+ const length = kept[i].end - kept[i].start;
51
+ if (p < offsets[i] + length) return kept[i].start + (p - offsets[i]);
52
+ }
53
+ return kept[kept.length - 1].end;
54
+ };
55
+ return {
56
+ windowStart,
57
+ windowEnd,
58
+ cuts,
59
+ hasCuts: cuts.length > 0,
60
+ playedDuration,
61
+ keptRanges: () => kept.map((r) => ({ ...r })),
62
+ sourceToPlayed,
63
+ snapSourceToPlayed,
64
+ playedToSource
65
+ };
66
+ }
67
+
68
+ export {
69
+ createMediaTimeMap
70
+ };
@@ -0,0 +1,230 @@
1
+ // src/mediaEdit/recipe.ts
2
+ var MEDIA_FX_ORDER = ["highpass", "denoise", "debreath", "loudness"];
3
+ var MEDIA_FX_SPECS = Object.freeze({
4
+ highpass: { defaultValue: 80, min: 20, max: 300 },
5
+ denoise: { defaultValue: 0.8, min: 0, max: 1 },
6
+ debreath: { defaultValue: -15, min: -40, max: 0 },
7
+ loudness: { defaultValue: -16, min: -31, max: -5 }
8
+ });
9
+ var MEDIA_EDIT_PARAMS = [
10
+ { key: "fx", htmlSuffix: "fx" },
11
+ { key: "cuts", htmlSuffix: "cuts" },
12
+ { key: "gain", htmlSuffix: "gain" },
13
+ { key: "fadeIn", htmlSuffix: "fade-in" },
14
+ { key: "fadeOut", htmlSuffix: "fade-out" },
15
+ { key: "crop", htmlSuffix: "crop" },
16
+ { key: "group", htmlSuffix: "group" }
17
+ ];
18
+ function mediaEditHtmlAttribute(kind, key) {
19
+ const param = MEDIA_EDIT_PARAMS.find((p) => p.key === key);
20
+ return `data-squisq-${kind}-${param?.htmlSuffix ?? key}`;
21
+ }
22
+ function formatMediaNumber(value, digits = 3) {
23
+ const rounded = Number(value.toFixed(digits));
24
+ return Object.is(rounded, -0) ? "0" : String(rounded);
25
+ }
26
+ function finiteNumber(raw) {
27
+ if (raw == null) return null;
28
+ const trimmed = raw.trim();
29
+ if (!/^[-+]?(\d+(\.\d*)?|\.\d+)$/.test(trimmed)) return null;
30
+ const n = Number(trimmed);
31
+ return Number.isFinite(n) ? n : null;
32
+ }
33
+ function clamp(value, min, max) {
34
+ return Math.min(max, Math.max(min, value));
35
+ }
36
+ function parseSeconds(raw) {
37
+ const trimmed = raw.trim();
38
+ const bare = finiteNumber(trimmed);
39
+ if (bare != null) return bare >= 0 ? bare : null;
40
+ const ms = trimmed.match(/^(\d+(?:\.\d+)?)ms$/i);
41
+ if (ms) return Number(ms[1]) / 1e3;
42
+ const mmss = trimmed.match(/^(\d+):([0-5]?\d)(?:\.(\d+))?$/);
43
+ if (mmss) return Number(mmss[1]) * 60 + Number(mmss[2]) + Number(`0.${mmss[3] ?? "0"}`);
44
+ return null;
45
+ }
46
+ function isFxOpId(name) {
47
+ return MEDIA_FX_ORDER.includes(name);
48
+ }
49
+ function parseMediaFx(raw) {
50
+ if (raw == null) return null;
51
+ const tokens = raw.split(/[\s,]+/).filter(Boolean);
52
+ if (tokens.length === 0) return null;
53
+ const byId = /* @__PURE__ */ new Map();
54
+ const unknown = [];
55
+ for (const token of tokens) {
56
+ const colon = token.indexOf(":");
57
+ const name = (colon === -1 ? token : token.slice(0, colon)).toLowerCase();
58
+ if (!isFxOpId(name)) {
59
+ unknown.push(token);
60
+ continue;
61
+ }
62
+ const spec = MEDIA_FX_SPECS[name];
63
+ let value = spec.defaultValue;
64
+ if (colon !== -1) {
65
+ value = finiteNumber(token.slice(colon + 1));
66
+ if (value != null && name === "debreath") value = -Math.abs(value);
67
+ }
68
+ if (value == null) {
69
+ unknown.push(token);
70
+ continue;
71
+ }
72
+ byId.set(name, clamp(value, spec.min, spec.max));
73
+ }
74
+ const ops = MEDIA_FX_ORDER.filter((id) => byId.has(id)).map((id) => ({
75
+ id,
76
+ value: byId.get(id)
77
+ }));
78
+ return { ops, unknown };
79
+ }
80
+ function serializeMediaFx(chain) {
81
+ return [
82
+ ...chain.ops.map((op) => `${op.id}:${formatMediaNumber(op.value)}`),
83
+ ...chain.unknown
84
+ ].join(" ");
85
+ }
86
+ function hasRenderableFx(chain) {
87
+ return chain != null && chain.ops.length > 0;
88
+ }
89
+ var CUT_EPSILON = 1e-3;
90
+ function normalizeMediaCuts(cuts, windowStart = 0, windowEnd = Number.POSITIVE_INFINITY) {
91
+ const clamped = cuts.filter((c) => Number.isFinite(c.start) && Number.isFinite(c.end)).map((c) => ({
92
+ start: Math.max(windowStart, Math.min(c.start, c.end)),
93
+ end: Math.min(windowEnd, Math.max(c.start, c.end))
94
+ })).filter((c) => c.end - c.start >= CUT_EPSILON).sort((a, b) => a.start - b.start);
95
+ const merged = [];
96
+ for (const cut of clamped) {
97
+ const last = merged[merged.length - 1];
98
+ if (last && cut.start <= last.end + CUT_EPSILON) {
99
+ last.end = Math.max(last.end, cut.end);
100
+ } else {
101
+ merged.push({ ...cut });
102
+ }
103
+ }
104
+ return merged;
105
+ }
106
+ function parseMediaCuts(raw) {
107
+ if (raw == null) return null;
108
+ const cuts = [];
109
+ for (const token of raw.split(/[\s,]+/).filter(Boolean)) {
110
+ const dash = token.indexOf("-", 1);
111
+ if (dash === -1) continue;
112
+ const start = parseSeconds(token.slice(0, dash));
113
+ const end = parseSeconds(token.slice(dash + 1));
114
+ if (start == null || end == null || end <= start) continue;
115
+ cuts.push({ start, end });
116
+ }
117
+ const normalized = normalizeMediaCuts(cuts);
118
+ return normalized.length > 0 ? normalized : null;
119
+ }
120
+ function serializeMediaCuts(cuts) {
121
+ return normalizeMediaCuts(cuts).map((c) => `${formatMediaNumber(c.start)}-${formatMediaNumber(c.end)}`).join(" ");
122
+ }
123
+ var MIN_CROP_EDGE = 0.02;
124
+ function parseMediaCrop(raw) {
125
+ if (raw == null) return null;
126
+ const parts = raw.split(/[\s,]+/).filter(Boolean).map((p) => finiteNumber(p));
127
+ if (parts.length !== 4 || parts.some((p) => p == null)) return null;
128
+ return normalizeMediaCrop({
129
+ x: parts[0],
130
+ y: parts[1],
131
+ w: parts[2],
132
+ h: parts[3]
133
+ });
134
+ }
135
+ function normalizeMediaCrop(crop) {
136
+ const x = clamp(crop.x, 0, 1 - MIN_CROP_EDGE);
137
+ const y = clamp(crop.y, 0, 1 - MIN_CROP_EDGE);
138
+ const w = clamp(crop.w, MIN_CROP_EDGE, 1 - x);
139
+ const h = clamp(crop.h, MIN_CROP_EDGE, 1 - y);
140
+ const full = x < 1e-4 && y < 1e-4 && w > 1 - 1e-4 && h > 1 - 1e-4;
141
+ return full ? null : { x, y, w, h };
142
+ }
143
+ function serializeMediaCrop(crop) {
144
+ return [crop.x, crop.y, crop.w, crop.h].map((n) => formatMediaNumber(n, 4)).join(" ");
145
+ }
146
+ var GAIN_RANGE = { min: -60, max: 24 };
147
+ var GROUP_RE = /^[A-Za-z0-9_-]{1,64}$/;
148
+ function parseMediaEdits(values) {
149
+ const edits = {};
150
+ const fx = parseMediaFx(values.fx);
151
+ if (fx && (fx.ops.length > 0 || fx.unknown.length > 0)) edits.fx = fx;
152
+ const cuts = parseMediaCuts(values.cuts);
153
+ if (cuts) edits.cuts = cuts;
154
+ const gain = finiteNumber(values.gain);
155
+ if (gain != null && gain !== 0) edits.gain = clamp(gain, GAIN_RANGE.min, GAIN_RANGE.max);
156
+ const fadeIn = values.fadeIn == null ? null : parseSeconds(values.fadeIn);
157
+ if (fadeIn != null && fadeIn > 0) edits.fadeIn = fadeIn;
158
+ const fadeOut = values.fadeOut == null ? null : parseSeconds(values.fadeOut);
159
+ if (fadeOut != null && fadeOut > 0) edits.fadeOut = fadeOut;
160
+ const crop = parseMediaCrop(values.crop);
161
+ if (crop) edits.crop = crop;
162
+ const group = values.group?.trim();
163
+ if (group && GROUP_RE.test(group)) edits.group = group;
164
+ return Object.keys(edits).length > 0 ? edits : void 0;
165
+ }
166
+ function serializeMediaEdits(edits) {
167
+ const fx = edits?.fx && (edits.fx.ops.length > 0 || edits.fx.unknown.length > 0);
168
+ return {
169
+ fx: fx && edits?.fx ? serializeMediaFx(edits.fx) : null,
170
+ cuts: edits?.cuts && edits.cuts.length > 0 ? serializeMediaCuts(edits.cuts) : null,
171
+ gain: edits?.gain ? formatMediaNumber(edits.gain, 2) : null,
172
+ fadeIn: edits?.fadeIn ? formatMediaNumber(edits.fadeIn) : null,
173
+ fadeOut: edits?.fadeOut ? formatMediaNumber(edits.fadeOut) : null,
174
+ crop: edits?.crop ? serializeMediaCrop(edits.crop) : null,
175
+ group: edits?.group ?? null
176
+ };
177
+ }
178
+ function mediaEditValuesFromParams(params) {
179
+ const out = {};
180
+ for (const { key } of MEDIA_EDIT_PARAMS) {
181
+ if (params[key] != null) out[key] = params[key];
182
+ }
183
+ return out;
184
+ }
185
+ function mediaEditValuesFromAttributes(kind, attributes) {
186
+ const out = {};
187
+ for (const { key } of MEDIA_EDIT_PARAMS) {
188
+ const value = attributes[mediaEditHtmlAttribute(kind, key)];
189
+ if (value != null) out[key] = value;
190
+ }
191
+ return out;
192
+ }
193
+ function fnv1a64Hex(text) {
194
+ let h1 = 2166136261;
195
+ let h2 = 16777619 ^ 1540483477;
196
+ for (let i = 0; i < text.length; i++) {
197
+ const c = text.charCodeAt(i);
198
+ h1 = Math.imul(h1 ^ c, 16777619);
199
+ h2 = Math.imul(h2 ^ c, 1540483477);
200
+ h2 ^= h2 >>> 15;
201
+ }
202
+ return (h1 >>> 0).toString(16).padStart(8, "0") + (h2 >>> 0).toString(16).padStart(8, "0");
203
+ }
204
+ function mediaRenderKey(src, fx) {
205
+ const canonical = fx.ops.map((op) => `${op.id}:${formatMediaNumber(op.value)}`).join(" ");
206
+ return fnv1a64Hex(`${src}
207
+ ${canonical}`).slice(0, 12);
208
+ }
209
+
210
+ export {
211
+ MEDIA_FX_ORDER,
212
+ MEDIA_FX_SPECS,
213
+ MEDIA_EDIT_PARAMS,
214
+ mediaEditHtmlAttribute,
215
+ formatMediaNumber,
216
+ parseMediaFx,
217
+ serializeMediaFx,
218
+ hasRenderableFx,
219
+ normalizeMediaCuts,
220
+ parseMediaCuts,
221
+ serializeMediaCuts,
222
+ parseMediaCrop,
223
+ normalizeMediaCrop,
224
+ serializeMediaCrop,
225
+ parseMediaEdits,
226
+ serializeMediaEdits,
227
+ mediaEditValuesFromParams,
228
+ mediaEditValuesFromAttributes,
229
+ mediaRenderKey
230
+ };