lumina-slides 8.9.4 → 9.0.0
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/LUMINA_LLM_EXAMPLES.json +234 -0
- package/README.md +18 -18
- package/dist/lumina-slides.js +13207 -12659
- package/dist/lumina-slides.umd.cjs +215 -215
- package/dist/style.css +1 -1
- package/package.json +5 -4
- package/src/App.vue +16 -0
- package/src/animation/index.ts +11 -0
- package/src/animation/registry.ts +126 -0
- package/src/animation/stagger.ts +95 -0
- package/src/animation/types.ts +53 -0
- package/src/components/LandingPage.vue +229 -0
- package/src/components/LuminaDeck.vue +224 -0
- package/src/components/LuminaSpeakerNotes.vue +701 -0
- package/src/components/base/BaseSlide.vue +122 -0
- package/src/components/base/LuminaElement.vue +67 -0
- package/src/components/base/VideoPlayer.vue +204 -0
- package/src/components/layouts/LayoutAuto.vue +71 -0
- package/src/components/layouts/LayoutChart.vue +287 -0
- package/src/components/layouts/LayoutCustom.vue +92 -0
- package/src/components/layouts/LayoutDiagram.vue +253 -0
- package/src/components/layouts/LayoutFeatures.vue +121 -0
- package/src/components/layouts/LayoutFlex.vue +172 -0
- package/src/components/layouts/LayoutFree.vue +62 -0
- package/src/components/layouts/LayoutHalf.vue +127 -0
- package/src/components/layouts/LayoutStatement.vue +74 -0
- package/src/components/layouts/LayoutSteps.vue +106 -0
- package/src/components/layouts/LayoutTimeline.vue +104 -0
- package/src/components/layouts/LayoutVideo.vue +41 -0
- package/src/components/parts/FlexBullets.vue +45 -0
- package/src/components/parts/FlexButton.vue +132 -0
- package/src/components/parts/FlexImage.vue +54 -0
- package/src/components/parts/FlexOrdered.vue +44 -0
- package/src/components/parts/FlexSpacer.vue +13 -0
- package/src/components/parts/FlexStepper.vue +59 -0
- package/src/components/parts/FlexText.vue +29 -0
- package/src/components/parts/FlexTimeline.vue +67 -0
- package/src/components/parts/FlexTitle.vue +39 -0
- package/src/components/parts/LuminaBackground.vue +100 -0
- package/src/components/site/LivePreview.vue +101 -0
- package/src/components/site/SiteApi.vue +301 -0
- package/src/components/site/SiteDashboard.vue +604 -0
- package/src/components/site/SiteDocs.vue +3267 -0
- package/src/components/site/SiteExamples.vue +65 -0
- package/src/components/site/SiteFooter.vue +6 -0
- package/src/components/site/SiteHome.vue +362 -0
- package/src/components/site/SiteNavBar.vue +122 -0
- package/src/components/site/SitePlayground.vue +389 -0
- package/src/components/site/SitePromptBuilder.vue +266 -0
- package/src/components/site/SiteUserMenu.vue +90 -0
- package/src/components/studio/ActionEditor.vue +108 -0
- package/src/components/studio/ArrayEditor.vue +124 -0
- package/src/components/studio/CollapsibleSection.vue +33 -0
- package/src/components/studio/ColorField.vue +22 -0
- package/src/components/studio/EditorCanvas.vue +326 -0
- package/src/components/studio/EditorLayoutFeatures.vue +18 -0
- package/src/components/studio/EditorLayoutFixed.vue +46 -0
- package/src/components/studio/EditorLayoutFlex.vue +133 -0
- package/src/components/studio/EditorLayoutHalf.vue +18 -0
- package/src/components/studio/EditorLayoutStatement.vue +18 -0
- package/src/components/studio/EditorLayoutSteps.vue +18 -0
- package/src/components/studio/EditorLayoutTimeline.vue +18 -0
- package/src/components/studio/EditorNode.vue +89 -0
- package/src/components/studio/FieldEditor.vue +133 -0
- package/src/components/studio/IconPicker.vue +109 -0
- package/src/components/studio/LayerItem.vue +117 -0
- package/src/components/studio/LuminaStudio.vue +30 -0
- package/src/components/studio/SaveSuccessModal.vue +138 -0
- package/src/components/studio/SlideNavigator.vue +373 -0
- package/src/components/studio/SliderField.vue +44 -0
- package/src/components/studio/StudioInspector.vue +595 -0
- package/src/components/studio/StudioJsonEditor.vue +191 -0
- package/src/components/studio/StudioLayers.vue +145 -0
- package/src/components/studio/StudioSettings.vue +514 -0
- package/src/components/studio/StudioSidebar.vue +29 -0
- package/src/components/studio/StudioToolbar.vue +222 -0
- package/src/components/studio/fieldLabels.ts +224 -0
- package/src/components/studio/inspectors/DiagramEdgeEditor.vue +77 -0
- package/src/components/studio/inspectors/DiagramNodeEditor.vue +117 -0
- package/src/components/studio/nodes/StudioDiagramNode.vue +138 -0
- package/src/composables/useAuth.ts +87 -0
- package/src/composables/useEditor.ts +224 -0
- package/src/composables/useElementState.ts +81 -0
- package/src/composables/useFlexLayout.ts +122 -0
- package/src/composables/useKeyboard.ts +45 -0
- package/src/composables/useLumina.ts +32 -0
- package/src/composables/useStudio.ts +87 -0
- package/src/composables/useSwipeNav.ts +53 -0
- package/src/composables/useTransition.ts +373 -0
- package/src/core/Lumina.ts +819 -0
- package/src/core/animationConfig.ts +251 -0
- package/src/core/compression.ts +34 -0
- package/src/core/elementController.ts +170 -0
- package/src/core/elementId.ts +27 -0
- package/src/core/elementResolver.ts +207 -0
- package/src/core/events.ts +53 -0
- package/src/core/fonts.ts +100 -0
- package/src/core/presets.ts +231 -0
- package/src/core/prompts.ts +272 -0
- package/src/core/schema.ts +478 -0
- package/src/core/speaker-channel.ts +250 -0
- package/src/core/store.ts +461 -0
- package/src/core/theme.ts +666 -0
- package/src/core/types.ts +1611 -0
- package/src/directives/vStudio.ts +45 -0
- package/src/index.ts +175 -0
- package/src/main.ts +17 -0
- package/src/router/index.ts +92 -0
- package/src/style/main.css +462 -0
- package/src/utils/deep.ts +127 -0
- package/src/utils/firebase.ts +184 -0
- package/src/utils/streaming.ts +134 -0
- package/src/views/DashboardView.vue +32 -0
- package/src/views/DeckView.vue +289 -0
- package/src/views/HomeView.vue +17 -0
- package/src/views/SiteLayout.vue +21 -0
- package/src/views/StudioView.vue +61 -0
- package/src/vite-env.d.ts +6 -0
- package/IMPLEMENTATION.md +0 -418
|
@@ -0,0 +1,1611 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LUMINA ENGINE TYPES
|
|
3
|
+
* Centralized type definitions for strict contract enforcement.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// --- Slide & Deck Definitions ---
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Supported slide layout types.
|
|
10
|
+
* Each type corresponds to a registered Vue component (e.g. 'statement' -> LayoutStatement).
|
|
11
|
+
*/
|
|
12
|
+
export type SlideType = 'statement' | 'half' | 'features' | 'timeline' | 'steps' | 'flex' | 'chart' | 'diagram' | 'free' | (string & {});
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Structure for items in the 'timeline' layout.
|
|
16
|
+
*/
|
|
17
|
+
export interface TimelineItem {
|
|
18
|
+
/** Optional id for element control (engine.element(id)). */
|
|
19
|
+
id?: string;
|
|
20
|
+
date: string;
|
|
21
|
+
title: string;
|
|
22
|
+
t?: string; // Alias for title
|
|
23
|
+
description: string;
|
|
24
|
+
desc?: string; // Alias for description
|
|
25
|
+
icon?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Structure for items in the 'steps' layout.
|
|
30
|
+
*/
|
|
31
|
+
export interface StepItem {
|
|
32
|
+
/** Optional id for element control (engine.element(id)). */
|
|
33
|
+
id?: string;
|
|
34
|
+
step: string; // e.g., "01"
|
|
35
|
+
title: string;
|
|
36
|
+
description?: string;
|
|
37
|
+
icon?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// --- Chart Layout Types ---
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Supported chart types.
|
|
44
|
+
*/
|
|
45
|
+
export type ChartType = 'bar' | 'line' | 'pie' | 'doughnut';
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* A single dataset for chart visualization.
|
|
49
|
+
*/
|
|
50
|
+
export interface ChartDataset {
|
|
51
|
+
/** Label for this dataset (appears in legend). */
|
|
52
|
+
label: string;
|
|
53
|
+
/** Numeric values corresponding to each label. */
|
|
54
|
+
values: number[];
|
|
55
|
+
/**
|
|
56
|
+
* Color for this dataset. Supports Lumina tokens:
|
|
57
|
+
* - 'c:p' → primary color
|
|
58
|
+
* - 'c:s' → secondary color
|
|
59
|
+
* - 'c:m' → muted color
|
|
60
|
+
* - Or any valid CSS color (hex, rgb, etc.)
|
|
61
|
+
*/
|
|
62
|
+
color?: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Data structure for chart visualization.
|
|
67
|
+
*/
|
|
68
|
+
export interface ChartData {
|
|
69
|
+
/** Labels for the x-axis or pie segments. */
|
|
70
|
+
labels: string[];
|
|
71
|
+
/** Array of datasets to display. */
|
|
72
|
+
datasets: ChartDataset[];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// --- Flex Layout Types ---
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Size tokens for flex element sizing.
|
|
79
|
+
* Determines how much horizontal/vertical space an element occupies.
|
|
80
|
+
*/
|
|
81
|
+
export type FlexSize = 'auto' | 'quarter' | 'third' | 'half' | 'two-thirds' | 'three-quarters' | 'full';
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Spacing tokens used for gaps and padding.
|
|
85
|
+
*/
|
|
86
|
+
export type SpacingToken = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Vertical alignment options.
|
|
90
|
+
*/
|
|
91
|
+
export type VAlign = 'top' | 'center' | 'bottom';
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Horizontal alignment options.
|
|
95
|
+
*/
|
|
96
|
+
export type HAlign = 'left' | 'center' | 'right';
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Text alignment options.
|
|
100
|
+
*/
|
|
101
|
+
export type TextAlign = 'left' | 'center' | 'right';
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Title element - Large heading text.
|
|
105
|
+
*/
|
|
106
|
+
export interface FlexElementTitle {
|
|
107
|
+
type: 'title';
|
|
108
|
+
/** Optional id for element control (engine.element(id)). */
|
|
109
|
+
id?: string;
|
|
110
|
+
text: string;
|
|
111
|
+
/** Heading size. Default: 'xl' */
|
|
112
|
+
size?: 'lg' | 'xl' | '2xl' | '3xl';
|
|
113
|
+
/** Text alignment. Default: 'left' */
|
|
114
|
+
align?: TextAlign;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Text element - Body paragraph text.
|
|
119
|
+
*/
|
|
120
|
+
export interface FlexElementText {
|
|
121
|
+
type: 'text';
|
|
122
|
+
/** Optional id for element control (engine.element(id)). */
|
|
123
|
+
id?: string;
|
|
124
|
+
text: string;
|
|
125
|
+
/** Text alignment. Default: 'left' */
|
|
126
|
+
align?: TextAlign;
|
|
127
|
+
/** Muted/subtle appearance. Default: false */
|
|
128
|
+
muted?: boolean;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Bullets element - Unordered list.
|
|
133
|
+
*/
|
|
134
|
+
export interface FlexElementBullets {
|
|
135
|
+
type: 'bullets';
|
|
136
|
+
/** Optional id for element control (engine.element(id)). */
|
|
137
|
+
id?: string;
|
|
138
|
+
items: string[];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Ordered element - Numbered list.
|
|
143
|
+
*/
|
|
144
|
+
export interface FlexElementOrdered {
|
|
145
|
+
type: 'ordered';
|
|
146
|
+
/** Optional id for element control (engine.element(id)). */
|
|
147
|
+
id?: string;
|
|
148
|
+
items: string[];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Image element - Visual media.
|
|
153
|
+
*/
|
|
154
|
+
export interface FlexElementImage {
|
|
155
|
+
type: 'image';
|
|
156
|
+
/** Optional id for element control (engine.element(id)). */
|
|
157
|
+
id?: string;
|
|
158
|
+
src: string;
|
|
159
|
+
alt?: string;
|
|
160
|
+
/** Fill entire container edge-to-edge. Default: true */
|
|
161
|
+
fill?: boolean;
|
|
162
|
+
/** Object-fit mode when fill is true. Default: 'cover' */
|
|
163
|
+
fit?: 'cover' | 'contain';
|
|
164
|
+
/** Border radius. Default: 'none' when fill, 'lg' otherwise */
|
|
165
|
+
rounded?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full';
|
|
166
|
+
/** Link URL when image is clicked. */
|
|
167
|
+
href?: string;
|
|
168
|
+
/** Link target. Default: '_blank' */
|
|
169
|
+
target?: '_blank' | '_self';
|
|
170
|
+
/** Custom CSS class */
|
|
171
|
+
class?: string;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Video element - Visual media.
|
|
176
|
+
*/
|
|
177
|
+
export interface FlexElementVideo extends VideoProperties {
|
|
178
|
+
type: 'video';
|
|
179
|
+
/** Optional id for element control (engine.element(id)). */
|
|
180
|
+
id?: string;
|
|
181
|
+
/** Fill entire container edge-to-edge. Default: true */
|
|
182
|
+
fill?: boolean;
|
|
183
|
+
/** Object-fit mode when fill is true. Default: 'cover' */
|
|
184
|
+
fit?: 'cover' | 'contain';
|
|
185
|
+
/** Border radius. Default: 'none' when fill, 'lg' otherwise */
|
|
186
|
+
rounded?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full';
|
|
187
|
+
/** Custom CSS class */
|
|
188
|
+
class?: string;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Button element - Call-to-action button.
|
|
193
|
+
*/
|
|
194
|
+
export interface FlexElementButton {
|
|
195
|
+
type: 'button';
|
|
196
|
+
/** Optional id for element control (engine.element(id)). */
|
|
197
|
+
id?: string;
|
|
198
|
+
label: string;
|
|
199
|
+
/** Action identifier emitted on click (for custom event handling). */
|
|
200
|
+
action?: string;
|
|
201
|
+
/** Type of action to perform. Default: 'event' */
|
|
202
|
+
actionType?: 'event' | 'url' | 'slide' | 'download';
|
|
203
|
+
/** URL to navigate to when actionType is 'url'. */
|
|
204
|
+
href?: string;
|
|
205
|
+
/** Slide index to navigate to when actionType is 'slide'. */
|
|
206
|
+
gotoSlide?: number;
|
|
207
|
+
/** Link target for URL actions. Default: '_blank' */
|
|
208
|
+
target?: '_blank' | '_self';
|
|
209
|
+
/** Visual variant. Default: 'primary' */
|
|
210
|
+
variant?: 'primary' | 'secondary' | 'outline' | 'ghost';
|
|
211
|
+
/** Full width button. Default: false */
|
|
212
|
+
fullWidth?: boolean;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Timeline element - Embedded timeline with events.
|
|
217
|
+
*/
|
|
218
|
+
export interface FlexElementTimeline {
|
|
219
|
+
type: 'timeline';
|
|
220
|
+
/** Optional id for element control (engine.element(id)). */
|
|
221
|
+
id?: string;
|
|
222
|
+
items: TimelineItem[];
|
|
223
|
+
/** Compact display mode. Default: false */
|
|
224
|
+
compact?: boolean;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Stepper element - Embedded step-by-step process.
|
|
229
|
+
*/
|
|
230
|
+
export interface FlexElementStepper {
|
|
231
|
+
type: 'stepper';
|
|
232
|
+
/** Optional id for element control (engine.element(id)). */
|
|
233
|
+
id?: string;
|
|
234
|
+
items: StepItem[];
|
|
235
|
+
/** Compact display mode. Default: false */
|
|
236
|
+
compact?: boolean;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Spacer element - Adds visual spacing.
|
|
241
|
+
*/
|
|
242
|
+
export interface FlexElementSpacer {
|
|
243
|
+
type: 'spacer';
|
|
244
|
+
/** Optional id for element control (engine.element(id)). */
|
|
245
|
+
id?: string;
|
|
246
|
+
/** Size of the space. Default: 'md' */
|
|
247
|
+
size?: SpacingToken;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Content container - Groups child elements vertically with alignment control.
|
|
252
|
+
*/
|
|
253
|
+
export interface FlexElementContent {
|
|
254
|
+
type: 'content';
|
|
255
|
+
/** Optional id for element control (engine.element(id)). */
|
|
256
|
+
id?: string;
|
|
257
|
+
elements: FlexChildElement[];
|
|
258
|
+
/** Vertical alignment of content. Default: 'center' */
|
|
259
|
+
valign?: VAlign;
|
|
260
|
+
/** Horizontal alignment of content. Default: 'left' */
|
|
261
|
+
halign?: HAlign;
|
|
262
|
+
/** Gap between child elements. Default: 'md' */
|
|
263
|
+
gap?: SpacingToken;
|
|
264
|
+
/** Internal padding. Default: 'lg' */
|
|
265
|
+
padding?: SpacingToken;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Child elements that can appear inside a content container.
|
|
270
|
+
*/
|
|
271
|
+
export type FlexChildElement =
|
|
272
|
+
| FlexElementTitle
|
|
273
|
+
| FlexElementText
|
|
274
|
+
| FlexElementBullets
|
|
275
|
+
| FlexElementOrdered
|
|
276
|
+
| FlexElementButton
|
|
277
|
+
| FlexElementTimeline
|
|
278
|
+
| FlexElementStepper
|
|
279
|
+
| FlexElementSpacer;
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Top-level flex elements that can have size.
|
|
283
|
+
*/
|
|
284
|
+
export type FlexElement =
|
|
285
|
+
| (FlexElementImage & { size?: FlexSize })
|
|
286
|
+
| (FlexElementVideo & { size?: FlexSize })
|
|
287
|
+
| (FlexElementContent & { size?: FlexSize })
|
|
288
|
+
| (FlexElementTitle & { size?: FlexSize })
|
|
289
|
+
| (FlexElementText & { size?: FlexSize })
|
|
290
|
+
| (FlexElementBullets & { size?: FlexSize })
|
|
291
|
+
| (FlexElementOrdered & { size?: FlexSize })
|
|
292
|
+
| (FlexElementButton & { size?: FlexSize })
|
|
293
|
+
| (FlexElementTimeline & { size?: FlexSize })
|
|
294
|
+
| (FlexElementStepper & { size?: FlexSize });
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Metadata for individual slides.
|
|
298
|
+
* Can contain arbitrary data used by custom layouts.
|
|
299
|
+
*/
|
|
300
|
+
export interface SlideMeta {
|
|
301
|
+
orbColor?: string;
|
|
302
|
+
orbPos?: { top: string; left: string };
|
|
303
|
+
[key: string]: any;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* State for a single controllable element (visibility, opacity, transform, etc.).
|
|
308
|
+
* Applied by LuminaElement / useElementState; written by `engine.element(id).show()`, `.hide()`, `.opacity()`, etc.
|
|
309
|
+
*
|
|
310
|
+
* Use `meta.initialElementState` in the deck to start with elements hidden and reveal them
|
|
311
|
+
* programmatically (e.g. presentation starts "empty", then `engine.element('s0-title').show()`).
|
|
312
|
+
*
|
|
313
|
+
* @example
|
|
314
|
+
* // In deck JSON: start slide 0 title and subtitle hidden; reveal via API.
|
|
315
|
+
* { "meta": { "title": "Demo", "initialElementState": { "s0-title": { "visible": false }, "s0-subtitle": { "visible": false } } }, "slides": [...] }
|
|
316
|
+
*
|
|
317
|
+
* @see ElementController
|
|
318
|
+
* @see DeckMeta.initialElementState
|
|
319
|
+
*/
|
|
320
|
+
export interface ElementState {
|
|
321
|
+
/** If false, the element is hidden (v-show). Omit or true = visible. */
|
|
322
|
+
visible?: boolean;
|
|
323
|
+
/** Opacity from 0 to 1. Applied as inline style. */
|
|
324
|
+
opacity?: number;
|
|
325
|
+
/** CSS transform (e.g. "scale(1.2)", "translateX(10px)"). */
|
|
326
|
+
transform?: string;
|
|
327
|
+
/** Extra CSS class names (space-separated). Merged with component classes. */
|
|
328
|
+
class?: string;
|
|
329
|
+
/** Inline style overrides. Merged with opacity/transform when those are set. */
|
|
330
|
+
style?: Record<string, string | number>;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Options for `ElementController.animate()` and `animateAsync()`. GSAP-compatible property names and values.
|
|
335
|
+
*
|
|
336
|
+
* @description
|
|
337
|
+
* `to` is required; `from` optional (animates from current state if omitted). `duration` and `ease` default
|
|
338
|
+
* to options.animation.elementDuration and elementEase (or resolveTransitionConfig). Element must be mounted (on the active slide).
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* engine.element('s0-title').animate({ to: { opacity: 1, y: 0 }, duration: 0.6, ease: 'power2.out' });
|
|
342
|
+
* engine.element('s1-features-0').animate({ from: { scale: 0 }, to: { scale: 1 }, duration: 0.5 });
|
|
343
|
+
* await engine.element('s0-tag').animateAsync({ to: { opacity: 1 }, onComplete: () => console.log('done') });
|
|
344
|
+
*
|
|
345
|
+
* @see ElementController.animate
|
|
346
|
+
* @see ElementController.animateAsync
|
|
347
|
+
*/
|
|
348
|
+
export interface AnimateOptions {
|
|
349
|
+
/** Preset name (fadeUp, scaleIn, slideLeft, etc.). Expands to from/to/ease; explicit from/to/ease override. */
|
|
350
|
+
preset?: string;
|
|
351
|
+
/** Motion name from meta.motions (future). Ignored if preset is set. */
|
|
352
|
+
motion?: string;
|
|
353
|
+
/** Starting values (GSAP from). If omitted, animates from current state or from preset. */
|
|
354
|
+
from?: Record<string, string | number>;
|
|
355
|
+
/** Target values (GSAP to). Optional when preset is set; preset provides to. */
|
|
356
|
+
to?: Record<string, string | number>;
|
|
357
|
+
/** Duration in seconds. Default from config or 0.5. */
|
|
358
|
+
duration?: number;
|
|
359
|
+
/** GSAP easing. Default from config or 'power2.out'. Preset provides default. */
|
|
360
|
+
ease?: string;
|
|
361
|
+
/** Callback when the animation completes. Also used by animateAsync. */
|
|
362
|
+
onComplete?: () => void;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Options for `Lumina.revealInSequence`. Controls staggered reveal of slide elements.
|
|
367
|
+
*
|
|
368
|
+
* @description
|
|
369
|
+
* When a value is omitted, it falls back to resolveTransitionConfig (revealDelayMs, revealDuration, revealEase).
|
|
370
|
+
* hideFirst: true (default) hides all elements before the sequence. only/exclude filter which ids are revealed.
|
|
371
|
+
*
|
|
372
|
+
* @example
|
|
373
|
+
* engine.revealInSequence(0, { delayMs: 500, animate: true });
|
|
374
|
+
* await engine.revealInSequence(undefined, { only: ['s1-title', 's1-subtitle'], hideFirst: true });
|
|
375
|
+
* engine.on('slideChange', e => engine.revealInSequence(e.index, { delayMs: 400, duration: 0.5 }));
|
|
376
|
+
*
|
|
377
|
+
* @see Lumina.revealInSequence
|
|
378
|
+
* @see resolveTransitionConfig
|
|
379
|
+
*/
|
|
380
|
+
export interface RevealInSequenceOptions {
|
|
381
|
+
/** Delay in ms between each element. Default: 400 */
|
|
382
|
+
delayMs?: number;
|
|
383
|
+
/** Stagger mode: sequential, center-out, ends-in, wave, random. Default: sequential. */
|
|
384
|
+
staggerMode?: 'sequential' | 'center-out' | 'ends-in' | 'wave' | 'random';
|
|
385
|
+
/** For staggerMode 'random', seed for deterministic order. Omit for arbitrary. */
|
|
386
|
+
randomSeed?: number;
|
|
387
|
+
/** Preset for each element's animation (fadeUp, scaleIn, etc.). Overridden by from/to/ease. */
|
|
388
|
+
preset?: string;
|
|
389
|
+
/** Motion from meta.motions (future). */
|
|
390
|
+
motion?: string;
|
|
391
|
+
/** Whether to animate each element on reveal. Default: true */
|
|
392
|
+
animate?: boolean;
|
|
393
|
+
/** GSAP from vars. Default: `{ opacity: 0, y: 16 }` or from preset. */
|
|
394
|
+
from?: Record<string, string | number>;
|
|
395
|
+
/** GSAP to vars. Default: `{ opacity: 1, y: 0 }` or from preset. */
|
|
396
|
+
to?: Record<string, string | number>;
|
|
397
|
+
/** Animation duration in seconds. Default: 0.45 */
|
|
398
|
+
duration?: number;
|
|
399
|
+
/** GSAP ease. Default: `'power2.out'` */
|
|
400
|
+
ease?: string;
|
|
401
|
+
/** If true, hide all elements before starting the sequence. Default: true */
|
|
402
|
+
hideFirst?: boolean;
|
|
403
|
+
/** Only reveal these element ids (subset). Order follows slide elements. */
|
|
404
|
+
only?: string[];
|
|
405
|
+
/** Exclude these element ids from the sequence. */
|
|
406
|
+
exclude?: string[];
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* State at a keyframe for timeline-driven animation. Used in `slide.timelineTracks[id]` and
|
|
411
|
+
* `element(id).animateToProgress(progress, keyframes)`. Keys are progress strings 0–1 (e.g. "0", "0.25", "1").
|
|
412
|
+
*
|
|
413
|
+
* @description
|
|
414
|
+
* Remotion-style: progress 0–1 drives element state. Interpolation is linear between keyframes.
|
|
415
|
+
* `x`, `y`, `scale` are mapped to a CSS transform. `visible: false` hides the element.
|
|
416
|
+
*
|
|
417
|
+
* @example
|
|
418
|
+
* { "0": { opacity: 0, y: 20 }, "0.3": { opacity: 1, y: 0 }, "1": { opacity: 1 } }
|
|
419
|
+
*
|
|
420
|
+
* @see TimelineTracks
|
|
421
|
+
* @see Lumina.seekTo
|
|
422
|
+
* @see ElementController.animateToProgress
|
|
423
|
+
*/
|
|
424
|
+
export type TimelineKeyframeState = Partial<{
|
|
425
|
+
opacity: number;
|
|
426
|
+
x: number;
|
|
427
|
+
y: number;
|
|
428
|
+
scale: number;
|
|
429
|
+
rotate: number;
|
|
430
|
+
visible: boolean;
|
|
431
|
+
}>;
|
|
432
|
+
|
|
433
|
+
/** Keyframes for one element: progress string -> state. */
|
|
434
|
+
export type TimelineKeyframes = Record<string, TimelineKeyframeState>;
|
|
435
|
+
|
|
436
|
+
/** Per-element timeline tracks. Keys = element ids. Use in `slide.timelineTracks`. */
|
|
437
|
+
export type TimelineTracks = Record<string, TimelineKeyframes>;
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Fluent API to control one slide element in real time. Returned by `engine.element(id)`
|
|
441
|
+
* and `engine.element(slideIndex, path)`. All methods return `this` for chaining.
|
|
442
|
+
*
|
|
443
|
+
* Use for: starting with an empty slide and revealing items in order, hiding highlights,
|
|
444
|
+
* animating entrances on demand, or syncing with voice/agent.
|
|
445
|
+
*
|
|
446
|
+
* @example
|
|
447
|
+
* // Reveal sequence (after loading a deck with initialElementState hiding s0-tag, s0-title, s0-subtitle)
|
|
448
|
+
* engine.element(0, 'tag').show();
|
|
449
|
+
* await delay(500);
|
|
450
|
+
* engine.element(0, 'title').show().animate({ from: { y: 20, opacity: 0 }, to: { y: 0, opacity: 1 }, duration: 0.5 });
|
|
451
|
+
* engine.element(0, 'subtitle').show();
|
|
452
|
+
*
|
|
453
|
+
* @see Lumina.element
|
|
454
|
+
* @see Lumina.elements
|
|
455
|
+
* @see ElementState
|
|
456
|
+
* @see AnimateOptions
|
|
457
|
+
*/
|
|
458
|
+
export interface ElementController {
|
|
459
|
+
/** Set visible = true. Use after starting with `initialElementState` { visible: false }. */
|
|
460
|
+
show(): ElementController;
|
|
461
|
+
/** Set visible = false. Element stays in DOM but is not displayed. */
|
|
462
|
+
hide(): ElementController;
|
|
463
|
+
/** Toggle visible. If `force` is given (true/false), set to that value. */
|
|
464
|
+
toggle(force?: boolean): ElementController;
|
|
465
|
+
/** Set opacity 0–1. Updates store; LuminaElement applies it. */
|
|
466
|
+
opacity(value: number): ElementController;
|
|
467
|
+
/** Set CSS transform string. */
|
|
468
|
+
transform(value: string): ElementController;
|
|
469
|
+
/** Merge props into element's style. Merged with existing style in the store. */
|
|
470
|
+
css(style: Record<string, string | number>): ElementController;
|
|
471
|
+
/** Append a CSS class to the element's state. */
|
|
472
|
+
addClass(className: string): ElementController;
|
|
473
|
+
/** Remove a CSS class from the element's state. */
|
|
474
|
+
removeClass(className: string): ElementController;
|
|
475
|
+
/** Run a GSAP animation on the DOM node. Element must be mounted (e.g. on that slide). */
|
|
476
|
+
animate(options: AnimateOptions): ElementController;
|
|
477
|
+
/** Like animate but returns a Promise that resolves when the animation completes. */
|
|
478
|
+
animateAsync(options: AnimateOptions): Promise<void>;
|
|
479
|
+
/**
|
|
480
|
+
* Set element state from a progress 0–1 by interpolating between keyframes. Remotion-style scrub.
|
|
481
|
+
* Use with `engine.seekTo(progress)` when the slide has `slide.timeline`.
|
|
482
|
+
*
|
|
483
|
+
* @param progress - 0–1. Interpolates between keyframes; keys are parseable numbers (e.g. "0", "0.3", "1").
|
|
484
|
+
* @param keyframes - Record of "progress" -> { opacity?, x?, y?, scale?, visible? }.
|
|
485
|
+
*/
|
|
486
|
+
animateToProgress(progress: number, keyframes: TimelineKeyframes): ElementController;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Base properties shared by all slides.
|
|
491
|
+
*/
|
|
492
|
+
interface SlideBase {
|
|
493
|
+
/** Unique ID for keying loop optimization (optional). */
|
|
494
|
+
id?: string;
|
|
495
|
+
/**
|
|
496
|
+
* Map of path keys to element ids. Use dot-notation for nested paths.
|
|
497
|
+
* Examples: { tag: "intro-tag" }, { "features.0": "hero-feature" }, { "elements.0.elements.1": "cta-btn" }.
|
|
498
|
+
* Overrides the default s{N}-{path} id when the target object has no explicit `id`.
|
|
499
|
+
*/
|
|
500
|
+
ids?: Record<string, string>;
|
|
501
|
+
/** Slide-specific metadata. */
|
|
502
|
+
meta?: SlideMeta;
|
|
503
|
+
/** Sizing mode: 'viewport' (100vh) or 'container' (100%). Default: 'viewport' */
|
|
504
|
+
sizing?: 'viewport' | 'container';
|
|
505
|
+
/**
|
|
506
|
+
* Timeline tracks per element (Remotion-style): id -> { "0": { opacity, y, ... }, "0.3": { ... }, "1": { ... } }.
|
|
507
|
+
* Use with `engine.seekTo(progress)` and `engine.playTimeline()`. Do not confuse with the "timeline" layout's `timeline: TimelineItem[]`.
|
|
508
|
+
*/
|
|
509
|
+
timelineTracks?: TimelineTracks;
|
|
510
|
+
/** Speaker notes for this slide (supports basic markdown). */
|
|
511
|
+
notes?: string;
|
|
512
|
+
/** Background image or video. */
|
|
513
|
+
background?: string | VideoProperties;
|
|
514
|
+
/** Opacity of the background (0-1). Default: 1 (or 0.2 for default dark overlay) */
|
|
515
|
+
backgroundOpacity?: number;
|
|
516
|
+
/** Optional custom CSS class for the slide content container. */
|
|
517
|
+
class?: string;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Common properties for video elements.
|
|
522
|
+
*/
|
|
523
|
+
export interface VideoProperties {
|
|
524
|
+
type: 'video';
|
|
525
|
+
src: string;
|
|
526
|
+
poster?: string;
|
|
527
|
+
/** Default: true for backgrounds, false for elements */
|
|
528
|
+
autoplay?: boolean;
|
|
529
|
+
/** Default: true for backgrounds, false for elements */
|
|
530
|
+
loop?: boolean;
|
|
531
|
+
/** Default: true for backgrounds, false for elements */
|
|
532
|
+
muted?: boolean;
|
|
533
|
+
/** Default: false */
|
|
534
|
+
controls?: boolean;
|
|
535
|
+
/** Custom CSS class */
|
|
536
|
+
className?: string;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Slide: Statement Layout
|
|
541
|
+
* A simple, high-impact text layout.
|
|
542
|
+
* @example
|
|
543
|
+
* ```json
|
|
544
|
+
* {
|
|
545
|
+
* "type": "statement",
|
|
546
|
+
* "meta": { "orbColor": "#3b82f6" },
|
|
547
|
+
* "tag": "Declarative Engine",
|
|
548
|
+
* "title": "Lumina V8",
|
|
549
|
+
* "subtitle": "A highly modular, performance-first presentation engine."
|
|
550
|
+
* }
|
|
551
|
+
* ```
|
|
552
|
+
*/
|
|
553
|
+
export interface SlideStatement extends SlideBase {
|
|
554
|
+
type: 'statement';
|
|
555
|
+
tag?: string;
|
|
556
|
+
title: string;
|
|
557
|
+
subtitle?: string;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Feature Item structure for Features Layout.
|
|
562
|
+
*/
|
|
563
|
+
export interface FeatureItem {
|
|
564
|
+
/** Optional id for element control (engine.element(id)). */
|
|
565
|
+
id?: string;
|
|
566
|
+
class: string;
|
|
567
|
+
title: string;
|
|
568
|
+
desc: string;
|
|
569
|
+
description?: string; // Alias for desc (backwards compatibility)
|
|
570
|
+
icon: string;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Slide: Features Layout
|
|
575
|
+
* A grid of feature cards.
|
|
576
|
+
* @example
|
|
577
|
+
* ```json
|
|
578
|
+
* {
|
|
579
|
+
* "type": "features",
|
|
580
|
+
* "title": "Core Capabilities",
|
|
581
|
+
* "description": "Built to scale.",
|
|
582
|
+
* "features": [
|
|
583
|
+
* { "title": "Reactive", "desc": "State management", "icon": "fa-database" },
|
|
584
|
+
* { "title": "Modular", "desc": "Tree-shakable", "icon": "fa-cube" }
|
|
585
|
+
* ]
|
|
586
|
+
* }
|
|
587
|
+
* ```
|
|
588
|
+
*/
|
|
589
|
+
export interface SlideFeatures extends SlideBase {
|
|
590
|
+
type: 'features';
|
|
591
|
+
title: string;
|
|
592
|
+
description?: string;
|
|
593
|
+
/** List of feature cards to display. */
|
|
594
|
+
features: FeatureItem[];
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Slide: Split/Half Layout
|
|
599
|
+
* Text on one side, image on the other.
|
|
600
|
+
* @example
|
|
601
|
+
* ```json
|
|
602
|
+
* {
|
|
603
|
+
* "type": "half",
|
|
604
|
+
* "imageSide": "left",
|
|
605
|
+
* "image": "https://example.com/photo.jpg",
|
|
606
|
+
* "title": "Smart Split Layouts",
|
|
607
|
+
* "paragraphs": ["Lumina adapts to viewport size.", "Content is King."],
|
|
608
|
+
* "cta": "Read Documentation"
|
|
609
|
+
* }
|
|
610
|
+
* ```
|
|
611
|
+
*/
|
|
612
|
+
export interface SlideHalf extends SlideBase {
|
|
613
|
+
imageClass: string;
|
|
614
|
+
type: 'half';
|
|
615
|
+
/** Which side the image appears on. */
|
|
616
|
+
imageSide: 'left' | 'right';
|
|
617
|
+
/** Image URL (optional if video is provided). */
|
|
618
|
+
image?: string;
|
|
619
|
+
/** Video properties (optional). */
|
|
620
|
+
video?: VideoProperties;
|
|
621
|
+
tag?: string;
|
|
622
|
+
title: string;
|
|
623
|
+
paragraphs: string[];
|
|
624
|
+
cta?: string;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* Slide: Timeline Layout
|
|
629
|
+
* Chronological list of events.
|
|
630
|
+
*/
|
|
631
|
+
export interface SlideTimeline extends SlideBase {
|
|
632
|
+
type: 'timeline';
|
|
633
|
+
title: string;
|
|
634
|
+
subtitle?: string;
|
|
635
|
+
timeline: TimelineItem[];
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Slide: Steps / Process Layout
|
|
640
|
+
* Numbered steps with descriptions.
|
|
641
|
+
*/
|
|
642
|
+
export interface SlideSteps extends SlideBase {
|
|
643
|
+
type: 'steps';
|
|
644
|
+
title: string;
|
|
645
|
+
subtitle?: string;
|
|
646
|
+
steps: StepItem[];
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Slide: Flex Layout
|
|
651
|
+
* Flow-based layout for composing slides using semantic sizing.
|
|
652
|
+
* Elements flow in order with size tokens (half, third, etc.) instead of coordinates.
|
|
653
|
+
* @example
|
|
654
|
+
* ```json
|
|
655
|
+
* {
|
|
656
|
+
* "type": "flex",
|
|
657
|
+
* "direction": "horizontal",
|
|
658
|
+
* "elements": [
|
|
659
|
+
* { "type": "image", "src": "photo.jpg", "size": "half", "fill": true },
|
|
660
|
+
* { "type": "content", "size": "half", "valign": "center", "elements": [
|
|
661
|
+
* { "type": "title", "text": "Hello World" },
|
|
662
|
+
* { "type": "bullets", "items": ["Point A", "Point B"] }
|
|
663
|
+
* ]}
|
|
664
|
+
* ]
|
|
665
|
+
* }
|
|
666
|
+
* ```
|
|
667
|
+
*/
|
|
668
|
+
export interface SlideFlex extends SlideBase {
|
|
669
|
+
type: 'flex';
|
|
670
|
+
/** Main flow direction. Default: 'horizontal' */
|
|
671
|
+
direction?: 'horizontal' | 'vertical';
|
|
672
|
+
/** Gap between top-level elements. Default: 'none' */
|
|
673
|
+
gap?: SpacingToken;
|
|
674
|
+
/** Padding around the entire container. Default: 'none' */
|
|
675
|
+
padding?: SpacingToken;
|
|
676
|
+
/** Horizontal alignment of the flex group within the slide. Default: 'left' */
|
|
677
|
+
halign?: HAlign;
|
|
678
|
+
/** Vertical alignment of the flex group within the slide. Default: 'top' */
|
|
679
|
+
valign?: VAlign;
|
|
680
|
+
/** Array of flex elements to render. */
|
|
681
|
+
elements: FlexElement[];
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Slide: Custom HTML
|
|
686
|
+
* Renders arbitrary HTML content fullscreen.
|
|
687
|
+
* Use with caution - HTML is injected directly.
|
|
688
|
+
* @example
|
|
689
|
+
* ```json
|
|
690
|
+
* {
|
|
691
|
+
* "type": "custom",
|
|
692
|
+
* "html": "<div class='my-custom-slide'>Custom Content</div>",
|
|
693
|
+
* "css": ".my-custom-slide { color: white; }"
|
|
694
|
+
* }
|
|
695
|
+
* ```
|
|
696
|
+
*/
|
|
697
|
+
export interface SlideCustom extends SlideBase {
|
|
698
|
+
type: 'custom';
|
|
699
|
+
/** Raw HTML content to render */
|
|
700
|
+
html: string;
|
|
701
|
+
/** Optional scoped CSS styles */
|
|
702
|
+
css?: string;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* Slide: Chart Layout
|
|
707
|
+
* Renders data visualizations using Chart.js.
|
|
708
|
+
* @example
|
|
709
|
+
* ```json
|
|
710
|
+
* {
|
|
711
|
+
* "type": "chart",
|
|
712
|
+
* "chartType": "bar",
|
|
713
|
+
* "title": "Revenue by Quarter",
|
|
714
|
+
* "data": {
|
|
715
|
+
* "labels": ["Q1", "Q2", "Q3", "Q4"],
|
|
716
|
+
* "datasets": [{ "label": "2024", "values": [120, 150, 180, 220], "color": "c:p" }]
|
|
717
|
+
* }
|
|
718
|
+
* }
|
|
719
|
+
* ```
|
|
720
|
+
*/
|
|
721
|
+
export interface SlideChart extends SlideBase {
|
|
722
|
+
chartClass: string;
|
|
723
|
+
type: 'chart';
|
|
724
|
+
/** The type of chart to render. */
|
|
725
|
+
chartType: ChartType;
|
|
726
|
+
/** Chart title displayed above the chart. */
|
|
727
|
+
title?: string;
|
|
728
|
+
/** Subtitle or description. */
|
|
729
|
+
subtitle?: string;
|
|
730
|
+
/** The chart data configuration. */
|
|
731
|
+
data: ChartData;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
/**
|
|
735
|
+
* Slide: Diagram Layout
|
|
736
|
+
* Renders an interactive node-based diagram.
|
|
737
|
+
*/
|
|
738
|
+
export interface SlideDiagram extends SlideBase {
|
|
739
|
+
type: 'diagram';
|
|
740
|
+
title?: string;
|
|
741
|
+
/** Diagram nodes (compatible with Vue Flow) */
|
|
742
|
+
nodes: any[];
|
|
743
|
+
/** Diagram edges (compatible with Vue Flow) */
|
|
744
|
+
edges: any[];
|
|
745
|
+
/** Optional configuration for the diagram engine */
|
|
746
|
+
config?: {
|
|
747
|
+
fitView?: boolean;
|
|
748
|
+
[key: string]: any;
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* Element in a free/composition layout. Absolutely positioned; position is driven by
|
|
754
|
+
* slide.timelineTracks (x, y as translate). Use for Remotion-style storytelling.
|
|
755
|
+
*/
|
|
756
|
+
export interface FreeElement {
|
|
757
|
+
id?: string;
|
|
758
|
+
type: 'text' | 'image' | 'box';
|
|
759
|
+
text?: string;
|
|
760
|
+
src?: string;
|
|
761
|
+
width?: number | string;
|
|
762
|
+
height?: number | string;
|
|
763
|
+
fontSize?: string | number;
|
|
764
|
+
color?: string;
|
|
765
|
+
fontWeight?: string;
|
|
766
|
+
backgroundColor?: string;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
/**
|
|
770
|
+
* Slide: Free / Composition (Remotion-style)
|
|
771
|
+
* Absolutely positioned elements (text, image, box) animated via timelineTracks.
|
|
772
|
+
* x, y in keyframes = translate; use for storytelling, motion, and layout freedom.
|
|
773
|
+
*/
|
|
774
|
+
export interface SlideFree extends SlideBase {
|
|
775
|
+
type: 'free';
|
|
776
|
+
elements: FreeElement[];
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
/**
|
|
780
|
+
* Slide: Generic / Custom
|
|
781
|
+
* Fallback for custom layouts or unknown types.
|
|
782
|
+
*/
|
|
783
|
+
export interface SlideGeneric extends SlideBase {
|
|
784
|
+
type: string & {};
|
|
785
|
+
[key: string]: any;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
/**
|
|
789
|
+
* Slide: Video Layout
|
|
790
|
+
* Full screen video player.
|
|
791
|
+
*/
|
|
792
|
+
export interface SlideVideo extends SlideBase {
|
|
793
|
+
type: 'video';
|
|
794
|
+
video: VideoProperties;
|
|
795
|
+
/** Optional caption or title overlay */
|
|
796
|
+
title?: string;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
/**
|
|
800
|
+
* The main Slide Data structure.
|
|
801
|
+
* A discriminated union of all supported slide types.
|
|
802
|
+
*/
|
|
803
|
+
export type BaseSlideData =
|
|
804
|
+
| SlideStatement
|
|
805
|
+
| SlideFeatures
|
|
806
|
+
| SlideHalf
|
|
807
|
+
| SlideTimeline
|
|
808
|
+
| SlideSteps
|
|
809
|
+
| SlideFlex
|
|
810
|
+
| SlideChart
|
|
811
|
+
| SlideDiagram
|
|
812
|
+
| SlideCustom
|
|
813
|
+
| SlideVideo
|
|
814
|
+
| SlideFree
|
|
815
|
+
| SlideGeneric;
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* Map of element id → partial ElementState. Used in `DeckMeta.initialElementState`
|
|
819
|
+
* to define initial visibility/opacity/transform when the deck loads. Enables
|
|
820
|
+
* "start empty, reveal on demand" presentations.
|
|
821
|
+
*/
|
|
822
|
+
export type InitialElementState = Record<string, Partial<ElementState>>;
|
|
823
|
+
|
|
824
|
+
/**
|
|
825
|
+
* Global metadata for the entire presentation deck.
|
|
826
|
+
*/
|
|
827
|
+
export interface DeckMeta {
|
|
828
|
+
id?: string; // Firestore document ID
|
|
829
|
+
title: string;
|
|
830
|
+
author?: string;
|
|
831
|
+
authorId?: string; // ID of the user who owns this deck
|
|
832
|
+
authorName?: string; // Display name of the author
|
|
833
|
+
isPublic?: boolean; // Visibility flag
|
|
834
|
+
date?: string;
|
|
835
|
+
deletedAt?: string; // Soft delete timestamp
|
|
836
|
+
/**
|
|
837
|
+
* Initial state for controllable elements when the deck is loaded. Keys are element ids
|
|
838
|
+
* (e.g. "s0-tag", "s0-title", "s1-features-0" or custom ids). Use { visible: false } to
|
|
839
|
+
* start hidden; then call engine.element(id).show() to reveal. Also supports opacity,
|
|
840
|
+
* transform, class, style. Overwritten on load; patchDeck does not reset it.
|
|
841
|
+
*
|
|
842
|
+
* @example
|
|
843
|
+
* "initialElementState": { "s0-tag": { "visible": false }, "s0-title": { "visible": false }, "s0-subtitle": { "visible": false } }
|
|
844
|
+
*
|
|
845
|
+
* @see ElementState
|
|
846
|
+
* @see Lumina.element
|
|
847
|
+
* @see getElementIds
|
|
848
|
+
*/
|
|
849
|
+
initialElementState?: InitialElementState;
|
|
850
|
+
/**
|
|
851
|
+
* Element control defaults. Can be set in deck JSON so the deck is self-contained.
|
|
852
|
+
* defaultVisible: false = start all elements hidden; override per-id via initialElementState.
|
|
853
|
+
*/
|
|
854
|
+
elementControl?: { defaultVisible?: boolean };
|
|
855
|
+
[key: string]: any;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* Complete deck object. Primary input to `engine.load(deck)`.
|
|
860
|
+
*
|
|
861
|
+
* @description
|
|
862
|
+
* Must have `meta.title` and `slides` (array of slide objects). meta.initialElementState and
|
|
863
|
+
* meta.elementControl enable reveal-on-demand. meta.effects overrides animation (see LuminaAnimationOptions).
|
|
864
|
+
*
|
|
865
|
+
* @example
|
|
866
|
+
* { meta: { title: "Demo", initialElementState: { "s0-title": { visible: false } } }, slides: [{ type: "statement", title: "Hi" }] }
|
|
867
|
+
*
|
|
868
|
+
* @see Lumina.load
|
|
869
|
+
* @see DeckMeta
|
|
870
|
+
* @see BaseSlideData
|
|
871
|
+
*/
|
|
872
|
+
export interface Deck {
|
|
873
|
+
meta: DeckMeta;
|
|
874
|
+
slides: BaseSlideData[];
|
|
875
|
+
/** Theme preset name or custom ThemeConfig object. */
|
|
876
|
+
theme?: string | ThemeConfig;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
// --- Configuration ---
|
|
880
|
+
|
|
881
|
+
// ============================================================================
|
|
882
|
+
// THEME CONFIGURATION TYPES
|
|
883
|
+
// Comprehensive design token system for full customization
|
|
884
|
+
// ============================================================================
|
|
885
|
+
|
|
886
|
+
/**
|
|
887
|
+
* Color palette configuration.
|
|
888
|
+
* All values should be Hex codes (e.g. '#EF4444') or valid CSS colors.
|
|
889
|
+
*/
|
|
890
|
+
export interface ThemeColors {
|
|
891
|
+
// --- Core Colors ---
|
|
892
|
+
/** Main brand/accent color. Used for highlights, buttons, links. */
|
|
893
|
+
primary?: string;
|
|
894
|
+
/** Secondary brand color. Used for complementary elements. */
|
|
895
|
+
secondary?: string;
|
|
896
|
+
/** Tertiary/accent color. Used for special highlights. */
|
|
897
|
+
accent?: string;
|
|
898
|
+
/** Main background color. */
|
|
899
|
+
background?: string;
|
|
900
|
+
/** Elevated surface color (cards, panels, modals). */
|
|
901
|
+
surface?: string;
|
|
902
|
+
/** Primary text color. */
|
|
903
|
+
text?: string;
|
|
904
|
+
/** Secondary/subdued text color. */
|
|
905
|
+
textSecondary?: string;
|
|
906
|
+
/** Muted/disabled text color. */
|
|
907
|
+
muted?: string;
|
|
908
|
+
|
|
909
|
+
// --- Semantic Colors ---
|
|
910
|
+
/** Success state color (green tones). */
|
|
911
|
+
success?: string;
|
|
912
|
+
/** Warning state color (yellow/amber tones). */
|
|
913
|
+
warning?: string;
|
|
914
|
+
/** Danger/error state color (red tones). */
|
|
915
|
+
danger?: string;
|
|
916
|
+
/** Informational state color (blue tones). */
|
|
917
|
+
info?: string;
|
|
918
|
+
|
|
919
|
+
// --- UI Element Colors ---
|
|
920
|
+
/** Border color for containers, cards, inputs. */
|
|
921
|
+
border?: string;
|
|
922
|
+
/** Subtle border color for dividers. */
|
|
923
|
+
borderSubtle?: string;
|
|
924
|
+
/** Shadow color (used with rgba). */
|
|
925
|
+
shadow?: string;
|
|
926
|
+
/** Overlay color for modals, backdrops. */
|
|
927
|
+
overlay?: string;
|
|
928
|
+
/** Highlight/selection color. */
|
|
929
|
+
highlight?: string;
|
|
930
|
+
|
|
931
|
+
// --- Interactive Element Colors ---
|
|
932
|
+
/** Primary button background. */
|
|
933
|
+
buttonPrimary?: string;
|
|
934
|
+
/** Primary button text. */
|
|
935
|
+
buttonPrimaryText?: string;
|
|
936
|
+
/** Secondary button background. */
|
|
937
|
+
buttonSecondary?: string;
|
|
938
|
+
/** Secondary button text. */
|
|
939
|
+
buttonSecondaryText?: string;
|
|
940
|
+
/** Link color. */
|
|
941
|
+
link?: string;
|
|
942
|
+
/** Link hover color. */
|
|
943
|
+
linkHover?: string;
|
|
944
|
+
|
|
945
|
+
// --- Gradient Colors ---
|
|
946
|
+
/** Gradient start color. */
|
|
947
|
+
gradientFrom?: string;
|
|
948
|
+
/** Gradient middle color (optional). */
|
|
949
|
+
gradientVia?: string;
|
|
950
|
+
/** Gradient end color. */
|
|
951
|
+
gradientTo?: string;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* Typography configuration.
|
|
956
|
+
*/
|
|
957
|
+
export interface ThemeTypography {
|
|
958
|
+
/** Font family definitions. */
|
|
959
|
+
fontFamily?: {
|
|
960
|
+
/** Font for headings (h1-h6, titles). */
|
|
961
|
+
heading?: string;
|
|
962
|
+
/** Font for body text, paragraphs. */
|
|
963
|
+
body?: string;
|
|
964
|
+
/** Font for code, monospace text. */
|
|
965
|
+
mono?: string;
|
|
966
|
+
};
|
|
967
|
+
/** Font size scale. Values should be CSS size values (rem, px, etc.). */
|
|
968
|
+
fontSize?: {
|
|
969
|
+
/** Extra small: 0.75rem / 12px */
|
|
970
|
+
xs?: string;
|
|
971
|
+
/** Small: 0.875rem / 14px */
|
|
972
|
+
sm?: string;
|
|
973
|
+
/** Base: 1rem / 16px */
|
|
974
|
+
base?: string;
|
|
975
|
+
/** Large: 1.125rem / 18px */
|
|
976
|
+
lg?: string;
|
|
977
|
+
/** Extra large: 1.25rem / 20px */
|
|
978
|
+
xl?: string;
|
|
979
|
+
/** 2XL: 1.5rem / 24px */
|
|
980
|
+
'2xl'?: string;
|
|
981
|
+
/** 3XL: 1.875rem / 30px */
|
|
982
|
+
'3xl'?: string;
|
|
983
|
+
/** 4XL: 2.25rem / 36px */
|
|
984
|
+
'4xl'?: string;
|
|
985
|
+
/** 5XL: 3rem / 48px */
|
|
986
|
+
'5xl'?: string;
|
|
987
|
+
/** 6XL: 3.75rem / 60px */
|
|
988
|
+
'6xl'?: string;
|
|
989
|
+
/** 7XL: 4.5rem / 72px */
|
|
990
|
+
'7xl'?: string;
|
|
991
|
+
};
|
|
992
|
+
/** Font weight scale. Values should be numeric (100-900). */
|
|
993
|
+
fontWeight?: {
|
|
994
|
+
/** Light weight: 300 */
|
|
995
|
+
light?: number;
|
|
996
|
+
/** Normal weight: 400 */
|
|
997
|
+
normal?: number;
|
|
998
|
+
/** Medium weight: 500 */
|
|
999
|
+
medium?: number;
|
|
1000
|
+
/** Semibold weight: 600 */
|
|
1001
|
+
semibold?: number;
|
|
1002
|
+
/** Bold weight: 700 */
|
|
1003
|
+
bold?: number;
|
|
1004
|
+
/** Extra bold weight: 800 */
|
|
1005
|
+
extrabold?: number;
|
|
1006
|
+
};
|
|
1007
|
+
/** Line height scale. Values should be unitless or CSS values. */
|
|
1008
|
+
lineHeight?: {
|
|
1009
|
+
/** Tight: 1.1 */
|
|
1010
|
+
tight?: string;
|
|
1011
|
+
/** Snug: 1.25 */
|
|
1012
|
+
snug?: string;
|
|
1013
|
+
/** Normal: 1.5 */
|
|
1014
|
+
normal?: string;
|
|
1015
|
+
/** Relaxed: 1.625 */
|
|
1016
|
+
relaxed?: string;
|
|
1017
|
+
/** Loose: 2 */
|
|
1018
|
+
loose?: string;
|
|
1019
|
+
};
|
|
1020
|
+
/** Letter spacing scale. Values should be CSS values (em, px). */
|
|
1021
|
+
letterSpacing?: {
|
|
1022
|
+
/** Tighter: -0.05em */
|
|
1023
|
+
tighter?: string;
|
|
1024
|
+
/** Tight: -0.025em */
|
|
1025
|
+
tight?: string;
|
|
1026
|
+
/** Normal: 0 */
|
|
1027
|
+
normal?: string;
|
|
1028
|
+
/** Wide: 0.025em */
|
|
1029
|
+
wide?: string;
|
|
1030
|
+
/** Wider: 0.05em */
|
|
1031
|
+
wider?: string;
|
|
1032
|
+
/** Widest: 0.1em (tracking-widest for labels) */
|
|
1033
|
+
widest?: string;
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
/**
|
|
1038
|
+
* Spacing scale configuration.
|
|
1039
|
+
* Values should be CSS size values (rem, px, etc.).
|
|
1040
|
+
*/
|
|
1041
|
+
export interface ThemeSpacing {
|
|
1042
|
+
/** 0 */
|
|
1043
|
+
none?: string;
|
|
1044
|
+
/** 0.25rem / 4px */
|
|
1045
|
+
xs?: string;
|
|
1046
|
+
/** 0.5rem / 8px */
|
|
1047
|
+
sm?: string;
|
|
1048
|
+
/** 1rem / 16px */
|
|
1049
|
+
md?: string;
|
|
1050
|
+
/** 1.5rem / 24px */
|
|
1051
|
+
lg?: string;
|
|
1052
|
+
/** 2rem / 32px */
|
|
1053
|
+
xl?: string;
|
|
1054
|
+
/** 3rem / 48px */
|
|
1055
|
+
'2xl'?: string;
|
|
1056
|
+
/** 4rem / 64px */
|
|
1057
|
+
'3xl'?: string;
|
|
1058
|
+
/** 6rem / 96px */
|
|
1059
|
+
'4xl'?: string;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
/**
|
|
1063
|
+
* Border radius scale configuration.
|
|
1064
|
+
* Values should be CSS size values (rem, px, etc.).
|
|
1065
|
+
*/
|
|
1066
|
+
export interface ThemeBorderRadius {
|
|
1067
|
+
/** No rounding: 0 */
|
|
1068
|
+
none?: string;
|
|
1069
|
+
/** Small: 0.25rem / 4px */
|
|
1070
|
+
sm?: string;
|
|
1071
|
+
/** Medium: 0.5rem / 8px */
|
|
1072
|
+
md?: string;
|
|
1073
|
+
/** Large: 0.75rem / 12px */
|
|
1074
|
+
lg?: string;
|
|
1075
|
+
/** Extra large: 1rem / 16px */
|
|
1076
|
+
xl?: string;
|
|
1077
|
+
/** 2XL: 1.5rem / 24px */
|
|
1078
|
+
'2xl'?: string;
|
|
1079
|
+
/** 3XL: 2rem / 32px */
|
|
1080
|
+
'3xl'?: string;
|
|
1081
|
+
/** Full circle/pill: 9999px */
|
|
1082
|
+
full?: string;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
/**
|
|
1086
|
+
* Visual effects configuration.
|
|
1087
|
+
*/
|
|
1088
|
+
export interface ThemeEffects {
|
|
1089
|
+
// --- Gradients ---
|
|
1090
|
+
/** Enable/disable gradient effects globally. */
|
|
1091
|
+
useGradients?: boolean;
|
|
1092
|
+
/** Gradient direction. */
|
|
1093
|
+
gradientDirection?: 'to-t' | 'to-b' | 'to-l' | 'to-r' | 'to-tl' | 'to-tr' | 'to-bl' | 'to-br';
|
|
1094
|
+
/** Override gradient start color (uses colors.gradientFrom if not set). */
|
|
1095
|
+
gradientFrom?: string;
|
|
1096
|
+
/** Override gradient via/middle color. */
|
|
1097
|
+
gradientVia?: string;
|
|
1098
|
+
/** Override gradient end color (uses colors.gradientTo if not set). */
|
|
1099
|
+
gradientTo?: string;
|
|
1100
|
+
|
|
1101
|
+
// --- Shadows ---
|
|
1102
|
+
/** Enable/disable shadow effects globally. */
|
|
1103
|
+
useShadows?: boolean;
|
|
1104
|
+
/** Shadow intensity level. */
|
|
1105
|
+
shadowIntensity?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
|
1106
|
+
/** Shadow color (supports CSS color). */
|
|
1107
|
+
shadowColor?: string;
|
|
1108
|
+
|
|
1109
|
+
// --- Glass/Blur Effect ---
|
|
1110
|
+
/** Enable/disable glassmorphism effect on panels. */
|
|
1111
|
+
useGlass?: boolean;
|
|
1112
|
+
/** Glass panel opacity (0-1). */
|
|
1113
|
+
glassOpacity?: number;
|
|
1114
|
+
/** Glass blur amount (e.g., "20px"). */
|
|
1115
|
+
glassBlur?: string;
|
|
1116
|
+
/** Glass border opacity (0-1). */
|
|
1117
|
+
glassBorderOpacity?: number;
|
|
1118
|
+
|
|
1119
|
+
// --- Ambient Orb/Glow ---
|
|
1120
|
+
/** Enable/disable ambient orb effect. */
|
|
1121
|
+
useOrb?: boolean;
|
|
1122
|
+
/** Orb opacity (0-1). */
|
|
1123
|
+
orbOpacity?: number;
|
|
1124
|
+
/** Orb blur amount (e.g., "120px"). */
|
|
1125
|
+
orbBlur?: string;
|
|
1126
|
+
/** Orb size (e.g., "60vw"). */
|
|
1127
|
+
orbSize?: string;
|
|
1128
|
+
|
|
1129
|
+
// --- Animations ---
|
|
1130
|
+
/** Enable/disable animations globally. */
|
|
1131
|
+
animationsEnabled?: boolean;
|
|
1132
|
+
/** Default transition duration (e.g., "0.3s"). */
|
|
1133
|
+
transitionDuration?: string;
|
|
1134
|
+
/** Default transition easing (e.g., "ease-out", CSS cubic-bezier). */
|
|
1135
|
+
transitionEasing?: string;
|
|
1136
|
+
/** Hover scale factor (e.g., 1.05 for 5% scale up). */
|
|
1137
|
+
hoverScale?: number;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
/**
|
|
1141
|
+
* Component-specific theming configuration.
|
|
1142
|
+
*/
|
|
1143
|
+
export interface ThemeComponents {
|
|
1144
|
+
// --- Buttons ---
|
|
1145
|
+
/** Button border radius token or CSS value. */
|
|
1146
|
+
buttonRadius?: string;
|
|
1147
|
+
/** Button padding (e.g., "0.75rem 1.5rem"). */
|
|
1148
|
+
buttonPadding?: string;
|
|
1149
|
+
/** Button font weight. */
|
|
1150
|
+
buttonFontWeight?: number;
|
|
1151
|
+
/** Button text transform (uppercase, capitalize, none). */
|
|
1152
|
+
buttonTextTransform?: 'none' | 'uppercase' | 'capitalize';
|
|
1153
|
+
|
|
1154
|
+
// --- Cards/Panels ---
|
|
1155
|
+
/** Card border radius token or CSS value. */
|
|
1156
|
+
cardRadius?: string;
|
|
1157
|
+
/** Card padding. */
|
|
1158
|
+
cardPadding?: string;
|
|
1159
|
+
/** Card border width (e.g., "1px"). */
|
|
1160
|
+
cardBorderWidth?: string;
|
|
1161
|
+
/** Card background (can override surface color). */
|
|
1162
|
+
cardBackground?: string;
|
|
1163
|
+
|
|
1164
|
+
// --- Timeline ---
|
|
1165
|
+
/** Timeline node/dot size (e.g., "1rem"). */
|
|
1166
|
+
timelineNodeSize?: string;
|
|
1167
|
+
/** Timeline connector line width (e.g., "2px"). */
|
|
1168
|
+
timelineLineWidth?: string;
|
|
1169
|
+
/** Timeline node color (uses primary if not set). */
|
|
1170
|
+
timelineNodeColor?: string;
|
|
1171
|
+
/** Timeline line color (uses border if not set). */
|
|
1172
|
+
timelineLineColor?: string;
|
|
1173
|
+
|
|
1174
|
+
// --- Steps ---
|
|
1175
|
+
/** Step number badge size. */
|
|
1176
|
+
stepBadgeSize?: string;
|
|
1177
|
+
/** Step number font size. */
|
|
1178
|
+
stepFontSize?: string;
|
|
1179
|
+
|
|
1180
|
+
// --- Progress Bar ---
|
|
1181
|
+
/** Progress bar height. */
|
|
1182
|
+
progressHeight?: string;
|
|
1183
|
+
/** Progress bar border radius. */
|
|
1184
|
+
progressRadius?: string;
|
|
1185
|
+
/** Progress bar background (track). */
|
|
1186
|
+
progressBackground?: string;
|
|
1187
|
+
/** Progress bar fill color. */
|
|
1188
|
+
progressFill?: string;
|
|
1189
|
+
|
|
1190
|
+
// --- Tags/Badges ---
|
|
1191
|
+
/** Tag padding. */
|
|
1192
|
+
tagPadding?: string;
|
|
1193
|
+
/** Tag border radius. */
|
|
1194
|
+
tagRadius?: string;
|
|
1195
|
+
/** Tag font size. */
|
|
1196
|
+
tagFontSize?: string;
|
|
1197
|
+
|
|
1198
|
+
// --- Input/Form Elements ---
|
|
1199
|
+
/** Input border radius. */
|
|
1200
|
+
inputRadius?: string;
|
|
1201
|
+
/** Input padding. */
|
|
1202
|
+
inputPadding?: string;
|
|
1203
|
+
/** Input border color. */
|
|
1204
|
+
inputBorder?: string;
|
|
1205
|
+
/** Input focus border color. */
|
|
1206
|
+
inputFocusBorder?: string;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
/**
|
|
1210
|
+
* Configuration for the visual theme.
|
|
1211
|
+
* Comprehensive design token system for full slide customization.
|
|
1212
|
+
*
|
|
1213
|
+
* @example
|
|
1214
|
+
* ```typescript
|
|
1215
|
+
* const theme: ThemeConfig = {
|
|
1216
|
+
* colors: {
|
|
1217
|
+
* primary: '#8b5cf6',
|
|
1218
|
+
* background: '#0a0a0a',
|
|
1219
|
+
* text: '#ffffff'
|
|
1220
|
+
* },
|
|
1221
|
+
* effects: {
|
|
1222
|
+
* useGradients: true,
|
|
1223
|
+
* useGlass: true,
|
|
1224
|
+
* glassBlur: '20px'
|
|
1225
|
+
* }
|
|
1226
|
+
* };
|
|
1227
|
+
* ```
|
|
1228
|
+
*/
|
|
1229
|
+
export interface ThemeConfig {
|
|
1230
|
+
/**
|
|
1231
|
+
* Color palette configuration.
|
|
1232
|
+
* Defines all colors used throughout the presentation.
|
|
1233
|
+
*/
|
|
1234
|
+
colors?: ThemeColors;
|
|
1235
|
+
|
|
1236
|
+
/**
|
|
1237
|
+
* Typography configuration.
|
|
1238
|
+
* Controls fonts, sizes, weights, and text styling.
|
|
1239
|
+
*/
|
|
1240
|
+
typography?: ThemeTypography;
|
|
1241
|
+
|
|
1242
|
+
/**
|
|
1243
|
+
* Spacing scale configuration.
|
|
1244
|
+
* Defines consistent spacing values for gaps, padding, margins.
|
|
1245
|
+
*/
|
|
1246
|
+
spacing?: ThemeSpacing;
|
|
1247
|
+
|
|
1248
|
+
/**
|
|
1249
|
+
* Border radius configuration.
|
|
1250
|
+
* Defines rounded corner values for UI elements.
|
|
1251
|
+
*/
|
|
1252
|
+
borderRadius?: ThemeBorderRadius;
|
|
1253
|
+
|
|
1254
|
+
/**
|
|
1255
|
+
* Visual effects configuration.
|
|
1256
|
+
* Controls gradients, shadows, glass effects, animations.
|
|
1257
|
+
*/
|
|
1258
|
+
effects?: ThemeEffects;
|
|
1259
|
+
|
|
1260
|
+
/**
|
|
1261
|
+
* Component-specific theming.
|
|
1262
|
+
* Fine-grained control over individual component styles.
|
|
1263
|
+
*/
|
|
1264
|
+
components?: ThemeComponents;
|
|
1265
|
+
|
|
1266
|
+
// Legacy support (mapped to new structure internally)
|
|
1267
|
+
/** @deprecated Use typography.fontFamily instead */
|
|
1268
|
+
fonts?: {
|
|
1269
|
+
heading?: string;
|
|
1270
|
+
body?: string;
|
|
1271
|
+
mono?: string;
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
/**
|
|
1276
|
+
* Custom keyboard shortcuts.
|
|
1277
|
+
*/
|
|
1278
|
+
export interface LuminaKeyBindings {
|
|
1279
|
+
next: string[];
|
|
1280
|
+
prev: string[];
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
/**
|
|
1284
|
+
* UI Visibility toggles.
|
|
1285
|
+
*/
|
|
1286
|
+
export interface LuminaUIOptions {
|
|
1287
|
+
visible?: boolean; // Global UI visibility
|
|
1288
|
+
showProgressBar?: boolean;
|
|
1289
|
+
showSlideCount?: boolean;
|
|
1290
|
+
showControls?: boolean; // Next/Prev buttons
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
/**
|
|
1294
|
+
* Animation configuration. All properties optional. Overrides apply in: options.animation, deck.meta.effects, slide.meta.effects.
|
|
1295
|
+
* Same keys are supported in meta.effects; legacy names (animationDuration→durationIn, etc.) are mapped. See resolveTransitionConfig.
|
|
1296
|
+
*
|
|
1297
|
+
* @description
|
|
1298
|
+
* Use when creating the engine: `new Lumina("#app", { animation: { durationIn: 1.2, revealDelayMs: 500 } })`.
|
|
1299
|
+
* Or in deck/slide JSON: `meta: { effects: { durationIn: 1, revealDelayMs: 400 } }`.
|
|
1300
|
+
*
|
|
1301
|
+
* @example
|
|
1302
|
+
* new Lumina("#app", { animation: { enabled: true, type: "cascade", durationIn: 1, revealDelayMs: 500, elementDuration: 0.6 } });
|
|
1303
|
+
*
|
|
1304
|
+
* @see resolveTransitionConfig
|
|
1305
|
+
* @see ANIMATION_DEFAULTS
|
|
1306
|
+
* @see ResolvedTransitionConfig
|
|
1307
|
+
*/
|
|
1308
|
+
export interface LuminaAnimationOptions {
|
|
1309
|
+
/** Global toggle for animations. */
|
|
1310
|
+
enabled?: boolean;
|
|
1311
|
+
/** The style of entry animation for slide elements. */
|
|
1312
|
+
type?: 'fade' | 'slide' | 'zoom' | 'cascade'; // Default: 'cascade'
|
|
1313
|
+
/** Duration of entry animations in seconds. */
|
|
1314
|
+
durationIn?: number;
|
|
1315
|
+
/** Duration of exit animations in seconds. */
|
|
1316
|
+
durationOut?: number;
|
|
1317
|
+
/** Stagger delay between sequential elements in seconds. */
|
|
1318
|
+
stagger?: number;
|
|
1319
|
+
/** GSAP easing string (e.g. 'power3.out'). */
|
|
1320
|
+
ease?: string;
|
|
1321
|
+
/**
|
|
1322
|
+
* If true, run the built-in GSAP reveal entrance on elements with .reveal-* classes.
|
|
1323
|
+
* Default: false. Also settable via meta.effects.entranceReveal.
|
|
1324
|
+
*/
|
|
1325
|
+
entranceReveal?: boolean;
|
|
1326
|
+
|
|
1327
|
+
// --- revealInSequence (engine.revealInSequence) ---
|
|
1328
|
+
/** Delay in ms between each element. Default: 400. */
|
|
1329
|
+
revealDelayMs?: number;
|
|
1330
|
+
/** Duration in seconds for each element's reveal. Default: 0.45. */
|
|
1331
|
+
revealDuration?: number;
|
|
1332
|
+
/** GSAP ease for reveal. Default: 'power2.out'. */
|
|
1333
|
+
revealEase?: string;
|
|
1334
|
+
|
|
1335
|
+
// --- element().animate() ---
|
|
1336
|
+
/** Default duration in seconds. Default: 0.5. */
|
|
1337
|
+
elementDuration?: number;
|
|
1338
|
+
/** Default GSAP ease. Default: 'power2.out'. */
|
|
1339
|
+
elementEase?: string;
|
|
1340
|
+
|
|
1341
|
+
// --- Exit / deck leave ---
|
|
1342
|
+
/** Ease for exit and slide leave. Default: 'power2.in'. */
|
|
1343
|
+
easeOut?: string;
|
|
1344
|
+
|
|
1345
|
+
// --- useTransition: entrance (granular) ---
|
|
1346
|
+
/** Image duration = durationIn * this. Default: 1.5. */
|
|
1347
|
+
imageDurationMultiplier?: number;
|
|
1348
|
+
/** Image reveal ease. Default: 'expo.out'. */
|
|
1349
|
+
imageEase?: string;
|
|
1350
|
+
/** Stagger between character spans (split text). Default: 0.015. */
|
|
1351
|
+
characterStagger?: number;
|
|
1352
|
+
/** Character duration = durationIn * this. Default: 0.8. */
|
|
1353
|
+
characterDurationFactor?: number;
|
|
1354
|
+
/** Character ease. Default: 'back.out(2)'. */
|
|
1355
|
+
characterEase?: string;
|
|
1356
|
+
/** Stagger between .reveal-child. Default: 0.05. */
|
|
1357
|
+
childRevealStagger?: number;
|
|
1358
|
+
/** Child duration = durationIn * this. Default: 0.6. */
|
|
1359
|
+
childRevealDurationFactor?: number;
|
|
1360
|
+
/** Timeline start offset for child reveal. Default: 0.2. */
|
|
1361
|
+
childRevealStart?: number;
|
|
1362
|
+
/** Child reveal ease. Default: 'power2.out'. */
|
|
1363
|
+
childRevealEase?: string;
|
|
1364
|
+
/** Fallback duration when type is not elastic. Default: 0.7. */
|
|
1365
|
+
durationInStandard?: number;
|
|
1366
|
+
/** Duration for elastic-up type. Default: 1.2. */
|
|
1367
|
+
durationInElastic?: number;
|
|
1368
|
+
/** Ease for elastic-up. Default: 'elastic.out(1, 0.5)'. */
|
|
1369
|
+
easeElastic?: string;
|
|
1370
|
+
/** Ease for spring type. Default: 'back.out(1.5)'. */
|
|
1371
|
+
easeSpring?: string;
|
|
1372
|
+
|
|
1373
|
+
// --- useTransition: exit ---
|
|
1374
|
+
/** Stagger between chars on exit. Default: 0.005. */
|
|
1375
|
+
exitCharStagger?: number;
|
|
1376
|
+
/** Exit element stagger = stagger * this. Default: 0.5. */
|
|
1377
|
+
exitStaggerFactor?: number;
|
|
1378
|
+
/** Exit image duration = durationOut * this. Default: 1.2. */
|
|
1379
|
+
exitImageDurationFactor?: number;
|
|
1380
|
+
/** Exit child duration = durationOut * this. Default: 0.8. */
|
|
1381
|
+
exitChildDurationFactor?: number;
|
|
1382
|
+
|
|
1383
|
+
// --- LuminaElement opacity transition ---
|
|
1384
|
+
/** CSS transition value for opacity (e.g. '0.35s ease-out'). Used via --lumina-element-opacity-transition. */
|
|
1385
|
+
elementOpacityTransition?: string;
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
/**
|
|
1389
|
+
* Options for `new Lumina(selector, options)`. All properties optional.
|
|
1390
|
+
*
|
|
1391
|
+
* @description
|
|
1392
|
+
* Controls theme (preset or ThemeConfig), loop, navigation, keyboard, touch, UI toggles, animation,
|
|
1393
|
+
* and elementControl (defaultVisible for reveal-on-demand). For animation overrides see LuminaAnimationOptions.
|
|
1394
|
+
*
|
|
1395
|
+
* @example
|
|
1396
|
+
* new Lumina("#app", { theme: "midnight", loop: true, animation: { durationIn: 1.2 } });
|
|
1397
|
+
* new Lumina("#app", { elementControl: { defaultVisible: false } });
|
|
1398
|
+
*
|
|
1399
|
+
* @see Lumina
|
|
1400
|
+
* @see LuminaAnimationOptions
|
|
1401
|
+
*/
|
|
1402
|
+
export interface LuminaOptions {
|
|
1403
|
+
/** CSS Selector for the container to mount into (default: '#app' or internal). */
|
|
1404
|
+
selector?: string;
|
|
1405
|
+
/** Whether to loop back to the start after the last slide. */
|
|
1406
|
+
loop?: boolean;
|
|
1407
|
+
/** Enable/Disable keyboard navigation. */
|
|
1408
|
+
navigation?: boolean;
|
|
1409
|
+
/** Enable/Disable keyboard shortcuts. */
|
|
1410
|
+
keyboard?: boolean;
|
|
1411
|
+
/** Enable/Disable touch swipe gestures. */
|
|
1412
|
+
touch?: boolean;
|
|
1413
|
+
/** Enable debug logs. */
|
|
1414
|
+
debug?: boolean;
|
|
1415
|
+
/** Theme configuration object or preset name string. */
|
|
1416
|
+
theme?: ThemeConfig | string;
|
|
1417
|
+
/** UI element toggles. */
|
|
1418
|
+
ui?: LuminaUIOptions;
|
|
1419
|
+
/** Custom key bindings. */
|
|
1420
|
+
keys?: LuminaKeyBindings;
|
|
1421
|
+
/** Animation settings. */
|
|
1422
|
+
animation?: LuminaAnimationOptions;
|
|
1423
|
+
/**
|
|
1424
|
+
* Element control defaults. Use for reveal-on-demand: set defaultVisible to false so all
|
|
1425
|
+
* elements start hidden; override per-id via meta.initialElementState. Then reveal with
|
|
1426
|
+
* engine.element(id).show().
|
|
1427
|
+
*/
|
|
1428
|
+
elementControl?: {
|
|
1429
|
+
/** If false, all elements start hidden unless listed in meta.initialElementState. Default: true. */
|
|
1430
|
+
defaultVisible?: boolean;
|
|
1431
|
+
};
|
|
1432
|
+
/** Enable Studio (Page Builder) mode. */
|
|
1433
|
+
studio?: boolean;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
// --- Events ---
|
|
1437
|
+
|
|
1438
|
+
/**
|
|
1439
|
+
* Supported event names emitted by the engine.
|
|
1440
|
+
*/
|
|
1441
|
+
export type LuminaEventType =
|
|
1442
|
+
| 'ready'
|
|
1443
|
+
| 'slideChange'
|
|
1444
|
+
| 'action'
|
|
1445
|
+
| 'error'
|
|
1446
|
+
| 'patch'
|
|
1447
|
+
| 'destroy'
|
|
1448
|
+
| 'navigate'
|
|
1449
|
+
| 'themeChange'
|
|
1450
|
+
| 'speakerNotesOpen'
|
|
1451
|
+
| 'speakerNotesClose'
|
|
1452
|
+
| 'timelineSeek'
|
|
1453
|
+
| 'timelineComplete'
|
|
1454
|
+
| 'revealStart'
|
|
1455
|
+
| 'revealComplete'
|
|
1456
|
+
| 'revealElement'
|
|
1457
|
+
| 'diagram-node-update'
|
|
1458
|
+
| 'studio:update';
|
|
1459
|
+
|
|
1460
|
+
/**
|
|
1461
|
+
* Payload for the 'slideChange' event.
|
|
1462
|
+
*/
|
|
1463
|
+
export interface SlideChangePayload {
|
|
1464
|
+
index: number;
|
|
1465
|
+
previousIndex: number;
|
|
1466
|
+
slide: BaseSlideData;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
/**
|
|
1470
|
+
* Payload for the 'action' event (e.g. button clicks).
|
|
1471
|
+
*/
|
|
1472
|
+
export interface ActionPayload {
|
|
1473
|
+
type: string;
|
|
1474
|
+
label?: string;
|
|
1475
|
+
value?: any;
|
|
1476
|
+
origin?: string; // Component ID
|
|
1477
|
+
/** Slide index for slide-update actions */
|
|
1478
|
+
slideIndex?: number;
|
|
1479
|
+
/** Patch object for slide-update actions (e.g., { nodes, edges }) */
|
|
1480
|
+
patch?: Record<string, any>;
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
/** Payload for the 'patch' event. Fired when engine.patch(diff) is called. */
|
|
1484
|
+
export interface PatchPayload {
|
|
1485
|
+
diff: any;
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
/** Payload for the 'navigate' event. Fired when next(), prev(), or goTo() changes the slide. */
|
|
1489
|
+
export interface NavigatePayload {
|
|
1490
|
+
direction: 'next' | 'prev' | 'goto';
|
|
1491
|
+
fromIndex: number;
|
|
1492
|
+
toIndex: number;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
/** Payload for the 'themeChange' event. Fired when theme or meta (colors, etc.) is applied. */
|
|
1496
|
+
export interface ThemeChangePayload {
|
|
1497
|
+
theme: string;
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
/** Payload for 'timelineSeek'. Fired when seekTo(progress) is called. */
|
|
1501
|
+
export interface TimelineSeekPayload {
|
|
1502
|
+
progress: number;
|
|
1503
|
+
slideIndex: number;
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
/** Payload for 'timelineComplete'. Fired when playTimeline finishes. */
|
|
1507
|
+
export interface TimelineCompletePayload {
|
|
1508
|
+
slideIndex: number;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
/** Payload for 'revealStart'. Fired when revealInSequence starts. */
|
|
1512
|
+
export interface RevealStartPayload {
|
|
1513
|
+
slideIndex: number;
|
|
1514
|
+
elementIds: string[];
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
/** Payload for 'revealComplete'. Fired when revealInSequence finishes. */
|
|
1518
|
+
export interface RevealCompletePayload {
|
|
1519
|
+
slideIndex: number;
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
/** Payload for 'revealElement'. Fired for each element as it is revealed in a sequence. */
|
|
1523
|
+
export interface RevealElementPayload {
|
|
1524
|
+
slideIndex: number;
|
|
1525
|
+
elementId: string;
|
|
1526
|
+
index: number;
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
/**
|
|
1530
|
+
* Event name → payload type map. Use with `engine.on(k, (payload) => ...)` for type-safe handlers.
|
|
1531
|
+
* - `ready`: deck loaded. - `slideChange`: active slide changed. - `action`: user action (e.g. button). - `error`: engine error.
|
|
1532
|
+
* - `patch`: deck patched (streaming). - `destroy`: engine destroyed. - `navigate`: next/prev/goTo changed slide.
|
|
1533
|
+
* - `themeChange`: theme or meta applied. - `speakerNotesOpen` / `speakerNotesClose`: speaker window.
|
|
1534
|
+
* - `timelineSeek` / `timelineComplete`: Remotion-style timeline. - `revealStart` / `revealComplete` / `revealElement`: revealInSequence.
|
|
1535
|
+
*/
|
|
1536
|
+
export interface LuminaEventMap {
|
|
1537
|
+
/** Fired when a deck is successfully loaded. */
|
|
1538
|
+
ready: Deck;
|
|
1539
|
+
/** Fired when the active slide changes. */
|
|
1540
|
+
slideChange: SlideChangePayload;
|
|
1541
|
+
/** Fired when a user interaction occurs. */
|
|
1542
|
+
action: ActionPayload;
|
|
1543
|
+
/** Fired when an internal or forwarded error occurs. Use engine.emitError(err) to forward. */
|
|
1544
|
+
error: Error;
|
|
1545
|
+
/** Fired when engine.patch(diff) is called. Useful for streaming or analytics. */
|
|
1546
|
+
patch: PatchPayload;
|
|
1547
|
+
/** Fired when engine.destroy() is called. Use for cleanup. */
|
|
1548
|
+
destroy: Record<string, never>;
|
|
1549
|
+
/** Fired when next(), prev(), or goTo() changes the slide. */
|
|
1550
|
+
navigate: NavigatePayload;
|
|
1551
|
+
/** Fired when theme or meta (colors, typography, etc.) is applied. */
|
|
1552
|
+
themeChange: ThemeChangePayload;
|
|
1553
|
+
/** Fired when the speaker notes window is opened. */
|
|
1554
|
+
speakerNotesOpen: Record<string, never>;
|
|
1555
|
+
/** Fired when the speaker notes window is closed. */
|
|
1556
|
+
speakerNotesClose: Record<string, never>;
|
|
1557
|
+
/** Fired when seekTo(progress) is called. */
|
|
1558
|
+
timelineSeek: TimelineSeekPayload;
|
|
1559
|
+
/** Fired when playTimeline(duration) finishes. */
|
|
1560
|
+
timelineComplete: TimelineCompletePayload;
|
|
1561
|
+
/** Fired when revealInSequence starts. */
|
|
1562
|
+
revealStart: RevealStartPayload;
|
|
1563
|
+
/** Fired when revealInSequence finishes. */
|
|
1564
|
+
revealComplete: RevealCompletePayload;
|
|
1565
|
+
/** Fired for each element as it is revealed in revealInSequence. */
|
|
1566
|
+
revealElement: RevealElementPayload;
|
|
1567
|
+
/** Fired to update a diagram node directly (bypasses store -> watch cycle). Internal. */
|
|
1568
|
+
'diagram-node-update': { slideIndex: number; nodeId: string; key: string; value: any };
|
|
1569
|
+
/** Fired when Studio updates a node (path, value). Internal. */
|
|
1570
|
+
'studio:update': { path: string; value: any };
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
/**
|
|
1574
|
+
* Key-value store exposed as `engine.data`. Persists across deck loads; not serialized.
|
|
1575
|
+
* Use for preferences, flags, or any app-specific state accessible from the engine or
|
|
1576
|
+
* from components via the injected store (getUserData/setUserData).
|
|
1577
|
+
*/
|
|
1578
|
+
export interface LuminaDataStore {
|
|
1579
|
+
get(key: string): unknown;
|
|
1580
|
+
set(key: string, value: unknown): LuminaDataStore;
|
|
1581
|
+
has(key: string): boolean;
|
|
1582
|
+
delete(key: string): boolean;
|
|
1583
|
+
clear(): void;
|
|
1584
|
+
keys(): string[];
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
// --- Speaker Notes ---
|
|
1588
|
+
|
|
1589
|
+
/**
|
|
1590
|
+
* Message payload for Speaker Notes cross-window synchronization.
|
|
1591
|
+
* Used by BroadcastChannel for bidirectional communication.
|
|
1592
|
+
*/
|
|
1593
|
+
export interface SpeakerSyncPayload {
|
|
1594
|
+
/** Action type for the sync message. */
|
|
1595
|
+
action: 'goto' | 'next' | 'prev' | 'state' | 'ping' | 'pong' | 'close';
|
|
1596
|
+
/** Current slide index (for 'goto' and 'state'). */
|
|
1597
|
+
index?: number;
|
|
1598
|
+
/** Total number of slides in the deck. */
|
|
1599
|
+
totalSlides?: number;
|
|
1600
|
+
/** Notes content for current slide. */
|
|
1601
|
+
currentNotes?: string;
|
|
1602
|
+
/** Preview info for the next slide. */
|
|
1603
|
+
nextSlidePreview?: {
|
|
1604
|
+
title?: string;
|
|
1605
|
+
type?: string;
|
|
1606
|
+
};
|
|
1607
|
+
/** Timestamp to prevent echo loops. */
|
|
1608
|
+
timestamp?: number;
|
|
1609
|
+
/** Channel ID for multi-instance support. */
|
|
1610
|
+
channelId?: string;
|
|
1611
|
+
}
|