@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.
- package/dist/{Doc-BkxT7G80.d.ts → Doc-DmElSKmg.d.ts} +219 -1
- package/dist/{ImageEditDoc-C8ZB54Vv.d.ts → ImageEditDoc-Dm_BETxC.d.ts} +1 -1
- package/dist/{chunk-EF353KGH.js → chunk-2PGC4JDT.js} +1 -1
- package/dist/{chunk-YGGYYBJS.js → chunk-B5STNW6C.js} +2 -2
- package/dist/{chunk-IYZTF4VO.js → chunk-CCRBHFNO.js} +3 -3
- package/dist/{chunk-VU4T74LI.js → chunk-DTM4FG7S.js} +1 -1
- package/dist/chunk-JSGIWW35.js +70 -0
- package/dist/chunk-L7QZORLB.js +230 -0
- package/dist/chunk-NEWNNLWN.js +64 -0
- package/dist/{chunk-6ECMNUIP.js → chunk-OU5FYBOB.js} +170 -4
- package/dist/{chunk-Y4D6TDZT.js → chunk-PCCQLD3G.js} +2 -0
- package/dist/{chunk-SKKBRLLM.js → chunk-QDA7NXDO.js} +7 -42
- package/dist/{chunk-3YNFMFNK.js → chunk-QOVINAB2.js} +18 -9
- package/dist/{chunk-SOIV7KDO.js → chunk-VRTXPGP7.js} +256 -26
- package/dist/{chunk-XJXBI3N5.js → chunk-XZVBR5BP.js} +1 -1
- package/dist/{chunk-GAZKTT4R.js → chunk-YNO6JV36.js} +96 -33
- package/dist/doc/index.d.ts +10 -6
- package/dist/doc/index.js +23 -21
- package/dist/fence/index.d.ts +1 -1
- package/dist/generate/index.d.ts +1 -1
- package/dist/imageEdit/index.d.ts +47 -4
- package/dist/imageEdit/index.js +5 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +52 -41
- package/dist/jsonForm/index.d.ts +1 -1
- package/dist/jsonForm/index.js +6 -4
- package/dist/markdown/index.js +3 -3
- package/dist/{materializePageSection-Dp2aHFbc.d.ts → materializePageSection-BfttC9Zj.d.ts} +6 -3
- package/dist/mediaEdit/index.d.ts +467 -0
- package/dist/mediaEdit/index.js +990 -0
- package/dist/narration/index.d.ts +20 -12
- package/dist/narration/index.js +7 -5
- package/dist/schemas/index.d.ts +4 -4
- package/dist/schemas/index.js +10 -4
- package/dist/{themeLibrary-BbSjnGmd.d.ts → themeLibrary-ChnTImby.d.ts} +1 -1
- package/dist/timing/index.d.ts +1 -1
- package/dist/transform/index.d.ts +2 -2
- package/dist/transform/index.js +7 -6
- package/package.json +6 -1
- 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
|
|
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,
|
|
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,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
defaultPageStyle
|
|
3
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
8
|
+
} from "./chunk-QOVINAB2.js";
|
|
9
9
|
import {
|
|
10
10
|
cloneAndFreezeData,
|
|
11
11
|
isTemplateBlock
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-PCCQLD3G.js";
|
|
13
13
|
import {
|
|
14
14
|
parseMarkdown
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-HUXK7EOT.js";
|
|
16
16
|
import {
|
|
17
17
|
extractPlainText,
|
|
18
18
|
getChildren
|
|
@@ -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
|
+
};
|