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.
Files changed (119) hide show
  1. package/LUMINA_LLM_EXAMPLES.json +234 -0
  2. package/README.md +18 -18
  3. package/dist/lumina-slides.js +13207 -12659
  4. package/dist/lumina-slides.umd.cjs +215 -215
  5. package/dist/style.css +1 -1
  6. package/package.json +5 -4
  7. package/src/App.vue +16 -0
  8. package/src/animation/index.ts +11 -0
  9. package/src/animation/registry.ts +126 -0
  10. package/src/animation/stagger.ts +95 -0
  11. package/src/animation/types.ts +53 -0
  12. package/src/components/LandingPage.vue +229 -0
  13. package/src/components/LuminaDeck.vue +224 -0
  14. package/src/components/LuminaSpeakerNotes.vue +701 -0
  15. package/src/components/base/BaseSlide.vue +122 -0
  16. package/src/components/base/LuminaElement.vue +67 -0
  17. package/src/components/base/VideoPlayer.vue +204 -0
  18. package/src/components/layouts/LayoutAuto.vue +71 -0
  19. package/src/components/layouts/LayoutChart.vue +287 -0
  20. package/src/components/layouts/LayoutCustom.vue +92 -0
  21. package/src/components/layouts/LayoutDiagram.vue +253 -0
  22. package/src/components/layouts/LayoutFeatures.vue +121 -0
  23. package/src/components/layouts/LayoutFlex.vue +172 -0
  24. package/src/components/layouts/LayoutFree.vue +62 -0
  25. package/src/components/layouts/LayoutHalf.vue +127 -0
  26. package/src/components/layouts/LayoutStatement.vue +74 -0
  27. package/src/components/layouts/LayoutSteps.vue +106 -0
  28. package/src/components/layouts/LayoutTimeline.vue +104 -0
  29. package/src/components/layouts/LayoutVideo.vue +41 -0
  30. package/src/components/parts/FlexBullets.vue +45 -0
  31. package/src/components/parts/FlexButton.vue +132 -0
  32. package/src/components/parts/FlexImage.vue +54 -0
  33. package/src/components/parts/FlexOrdered.vue +44 -0
  34. package/src/components/parts/FlexSpacer.vue +13 -0
  35. package/src/components/parts/FlexStepper.vue +59 -0
  36. package/src/components/parts/FlexText.vue +29 -0
  37. package/src/components/parts/FlexTimeline.vue +67 -0
  38. package/src/components/parts/FlexTitle.vue +39 -0
  39. package/src/components/parts/LuminaBackground.vue +100 -0
  40. package/src/components/site/LivePreview.vue +101 -0
  41. package/src/components/site/SiteApi.vue +301 -0
  42. package/src/components/site/SiteDashboard.vue +604 -0
  43. package/src/components/site/SiteDocs.vue +3267 -0
  44. package/src/components/site/SiteExamples.vue +65 -0
  45. package/src/components/site/SiteFooter.vue +6 -0
  46. package/src/components/site/SiteHome.vue +362 -0
  47. package/src/components/site/SiteNavBar.vue +122 -0
  48. package/src/components/site/SitePlayground.vue +389 -0
  49. package/src/components/site/SitePromptBuilder.vue +266 -0
  50. package/src/components/site/SiteUserMenu.vue +90 -0
  51. package/src/components/studio/ActionEditor.vue +108 -0
  52. package/src/components/studio/ArrayEditor.vue +124 -0
  53. package/src/components/studio/CollapsibleSection.vue +33 -0
  54. package/src/components/studio/ColorField.vue +22 -0
  55. package/src/components/studio/EditorCanvas.vue +326 -0
  56. package/src/components/studio/EditorLayoutFeatures.vue +18 -0
  57. package/src/components/studio/EditorLayoutFixed.vue +46 -0
  58. package/src/components/studio/EditorLayoutFlex.vue +133 -0
  59. package/src/components/studio/EditorLayoutHalf.vue +18 -0
  60. package/src/components/studio/EditorLayoutStatement.vue +18 -0
  61. package/src/components/studio/EditorLayoutSteps.vue +18 -0
  62. package/src/components/studio/EditorLayoutTimeline.vue +18 -0
  63. package/src/components/studio/EditorNode.vue +89 -0
  64. package/src/components/studio/FieldEditor.vue +133 -0
  65. package/src/components/studio/IconPicker.vue +109 -0
  66. package/src/components/studio/LayerItem.vue +117 -0
  67. package/src/components/studio/LuminaStudio.vue +30 -0
  68. package/src/components/studio/SaveSuccessModal.vue +138 -0
  69. package/src/components/studio/SlideNavigator.vue +373 -0
  70. package/src/components/studio/SliderField.vue +44 -0
  71. package/src/components/studio/StudioInspector.vue +595 -0
  72. package/src/components/studio/StudioJsonEditor.vue +191 -0
  73. package/src/components/studio/StudioLayers.vue +145 -0
  74. package/src/components/studio/StudioSettings.vue +514 -0
  75. package/src/components/studio/StudioSidebar.vue +29 -0
  76. package/src/components/studio/StudioToolbar.vue +222 -0
  77. package/src/components/studio/fieldLabels.ts +224 -0
  78. package/src/components/studio/inspectors/DiagramEdgeEditor.vue +77 -0
  79. package/src/components/studio/inspectors/DiagramNodeEditor.vue +117 -0
  80. package/src/components/studio/nodes/StudioDiagramNode.vue +138 -0
  81. package/src/composables/useAuth.ts +87 -0
  82. package/src/composables/useEditor.ts +224 -0
  83. package/src/composables/useElementState.ts +81 -0
  84. package/src/composables/useFlexLayout.ts +122 -0
  85. package/src/composables/useKeyboard.ts +45 -0
  86. package/src/composables/useLumina.ts +32 -0
  87. package/src/composables/useStudio.ts +87 -0
  88. package/src/composables/useSwipeNav.ts +53 -0
  89. package/src/composables/useTransition.ts +373 -0
  90. package/src/core/Lumina.ts +819 -0
  91. package/src/core/animationConfig.ts +251 -0
  92. package/src/core/compression.ts +34 -0
  93. package/src/core/elementController.ts +170 -0
  94. package/src/core/elementId.ts +27 -0
  95. package/src/core/elementResolver.ts +207 -0
  96. package/src/core/events.ts +53 -0
  97. package/src/core/fonts.ts +100 -0
  98. package/src/core/presets.ts +231 -0
  99. package/src/core/prompts.ts +272 -0
  100. package/src/core/schema.ts +478 -0
  101. package/src/core/speaker-channel.ts +250 -0
  102. package/src/core/store.ts +461 -0
  103. package/src/core/theme.ts +666 -0
  104. package/src/core/types.ts +1611 -0
  105. package/src/directives/vStudio.ts +45 -0
  106. package/src/index.ts +175 -0
  107. package/src/main.ts +17 -0
  108. package/src/router/index.ts +92 -0
  109. package/src/style/main.css +462 -0
  110. package/src/utils/deep.ts +127 -0
  111. package/src/utils/firebase.ts +184 -0
  112. package/src/utils/streaming.ts +134 -0
  113. package/src/views/DashboardView.vue +32 -0
  114. package/src/views/DeckView.vue +289 -0
  115. package/src/views/HomeView.vue +17 -0
  116. package/src/views/SiteLayout.vue +21 -0
  117. package/src/views/StudioView.vue +61 -0
  118. package/src/vite-env.d.ts +6 -0
  119. package/IMPLEMENTATION.md +0 -418
@@ -0,0 +1,45 @@
1
+ import { Directive, DirectiveBinding } from 'vue';
2
+
3
+ export const vStudio: Directive = {
4
+ mounted(el: HTMLElement, binding: DirectiveBinding) {
5
+ // binding.value should be the path string e.g. "elements.0.title"
6
+
7
+ // We use a data attribute to store the path for debugging/logic
8
+ el.dataset.studioPath = binding.value;
9
+
10
+ // Hover Effect
11
+ el.addEventListener('mouseenter', () => {
12
+ // Only if studio mode is enabled?
13
+ // We can check a global class on body or just always emit and let parent decide.
14
+ // Better: check if a specific class exists on a parent, or use a store if possible (hard in directive).
15
+ // For now, let's just add a class that we can style in CSS only when .studio-mode is active.
16
+ el.classList.add('studio-hover');
17
+ });
18
+
19
+ el.addEventListener('mouseleave', () => {
20
+ el.classList.remove('studio-hover');
21
+ });
22
+
23
+ // Click Handler
24
+ el.addEventListener('click', (e) => {
25
+ // We want to stop propagation so we select the most specific element
26
+ e.stopPropagation();
27
+
28
+ const rect = el.getBoundingClientRect();
29
+
30
+ const event = new CustomEvent('studio-select', {
31
+ bubbles: true,
32
+ detail: {
33
+ path: binding.value,
34
+ rect: rect
35
+ }
36
+ });
37
+
38
+ el.dispatchEvent(event);
39
+ });
40
+ },
41
+
42
+ updated(el: HTMLElement, binding: DirectiveBinding) {
43
+ el.dataset.studioPath = binding.value;
44
+ }
45
+ };
package/src/index.ts ADDED
@@ -0,0 +1,175 @@
1
+ /**
2
+ * lumina-slides — Renders declarative JSON into animated slide decks. Vanilla JS; Vue not required.
3
+ *
4
+ * ---
5
+ * ## Quick reference for LLMs and code agents
6
+ *
7
+ * **Entry:** `import { Lumina } from "lumina-slides"; import "lumina-slides/style.css";`
8
+ * `const engine = new Lumina("#app", options); engine.load(deck);`
9
+ *
10
+ * **Deck:** `{ meta: { title, initialElementState?, elementControl?, effects? }, slides: [...] }`
11
+ * Slide types: statement, features, half, timeline, steps, flex, chart, diagram, custom, video.
12
+ *
13
+ * **Element control:** `engine.element(id)` or `engine.element(slideIndex, path)` → ElementController:
14
+ * `.show()`, `.hide()`, `.toggle()`, `.opacity(n)`, `.transform(s)`, `.animate({ preset?, from?, to?, duration?, ease? })`.
15
+ * Presets: fadeUp, fadeIn, scaleIn, slideLeft, slideRight, zoomIn, blurIn, spring, drop, fadeOut. `to` optional when using preset.
16
+ * Ids: `engine.elements(slideIndex)` or `s{N}-{path}` (e.g. s0-tag, s1-features-0). `meta.initialElementState`:
17
+ * `{ [id]: { visible?: false } }` to start hidden; then `engine.element(id).show()`.
18
+ *
19
+ * **Helpers:** `hideAll(slideIndex?)`, `showAll(slideIndex?)`, `showOnly(ids?)`, `hideAllExcept(exceptIds?)`,
20
+ * `resetSlide(slideIndex?)`, `delay(ms)`, `revealInSequence(slideIndex?, { delayMs?, staggerMode?, preset?, from?, to?, duration?, ease?, hideFirst?, only?, exclude? })`.
21
+ * StaggerMode: sequential, center-out, ends-in, wave, random. Animation: `getPreset`, `registerPreset`, `computeStagger`, `BUILTIN_PRESETS`.
22
+ *
23
+ * **Timeline (Remotion-style):** `slide.timelineTracks` = `{ [id]: { "0": { opacity?, x?, y?, scale?, rotate?, visible? }, "0.3": {...}, "1": {...} } }`.
24
+ * `type: "free"` layout: `elements: [{ type: "text"|"image"|"box", text?, src?, width?, height?, ... }]` — absolute positioning, storytelling.
25
+ * `engine.seekTo(progress)`, `engine.playTimeline(duration?)` → `[Promise, cancel]`, `engine.timelineProgress`, `element(id).animateToProgress(progress, keyframes)`. Example: *Animation: Timeline* in Examples.
26
+ *
27
+ * **Animation config:** All timings/eases overridable via `options.animation`, `deck.meta.effects`, `slide.meta.effects`.
28
+ * `resolveTransitionConfig(store, slide?)` returns merged config. `ANIMATION_DEFAULTS` has all keys.
29
+ * Keys: durationIn, durationOut, stagger, ease, revealDelayMs, revealDuration, revealEase, elementDuration, elementEase, easeOut, etc.
30
+ *
31
+ * **Events:** `engine.on("ready"|"slideChange"|"action"|"error"|"patch"|"destroy"|"navigate"|"themeChange"|"speakerNotesOpen"|"speakerNotesClose"|"timelineSeek"|"timelineComplete"|"revealStart"|"revealComplete"|"revealElement", handler)`. `engine.emitError(err)` to forward errors.
32
+ * **State for LLM:** `engine.exportState()` → `{ currentSlide, narrative, history }`.
33
+ * **Key-value store:** `engine.data.get(key)`, `engine.data.set(key, value)`, `engine.data.has(key)`, `engine.data.delete(key)`, `engine.data.clear()`, `engine.data.keys()`. Persists across deck loads.
34
+ *
35
+ * **Streaming:** `parsePartialJson(buffer)` then `engine.load(json)`. Or `createDebouncedLoader(engine.load, ms)`.
36
+ * **Prompts:** `generateSystemPrompt({ mode, includeSchema, includeTheming })`, `generateThemePrompt()`.
37
+ * **Schema:** `getLuminaJsonSchema()`.
38
+ *
39
+ * **More:** IMPLEMENTATION.md, AGENTS.md, ELEMENT_IDS.md. Full JSDoc: this package includes `src/`; read
40
+ * `src/core/Lumina.ts`, `src/core/animationConfig.ts`, `src/core/types.ts`. Minified `dist/` strips comments.
41
+ */
42
+ export { Lumina } from './core/Lumina';
43
+
44
+ export type {
45
+ LuminaOptions,
46
+ LuminaDataStore,
47
+ Deck,
48
+ BaseSlideData as SlideData,
49
+ ThemeConfig,
50
+ LuminaEventMap,
51
+ // Detailed Types for Docs
52
+ DeckMeta,
53
+ // Slide Interfaces
54
+ SlideStatement,
55
+ SlideFeatures,
56
+ SlideHalf,
57
+ SlideTimeline,
58
+ SlideSteps,
59
+ SlideFlex,
60
+ SlideChart,
61
+ SlideFree,
62
+ SlideGeneric,
63
+ SlideCustom,
64
+ FreeElement,
65
+ FeatureItem,
66
+ StepItem,
67
+ TimelineItem,
68
+ SlideMeta,
69
+ LuminaEventType,
70
+ SlideChangePayload,
71
+ ActionPayload,
72
+ PatchPayload,
73
+ NavigatePayload,
74
+ ThemeChangePayload,
75
+ TimelineSeekPayload,
76
+ TimelineCompletePayload,
77
+ RevealStartPayload,
78
+ RevealCompletePayload,
79
+ RevealElementPayload,
80
+ LuminaUIOptions,
81
+ LuminaAnimationOptions,
82
+ LuminaKeyBindings,
83
+ // Chart Types
84
+ ChartType,
85
+ ChartData,
86
+ ChartDataset,
87
+ // Flex Types
88
+ FlexElement,
89
+ FlexChildElement,
90
+ FlexSize,
91
+ SpacingToken,
92
+ VAlign,
93
+ HAlign,
94
+ TextAlign,
95
+ FlexElementImage,
96
+ FlexElementContent,
97
+ FlexElementTitle,
98
+ FlexElementText,
99
+ FlexElementBullets,
100
+ FlexElementOrdered,
101
+ FlexElementButton,
102
+ FlexElementTimeline,
103
+ FlexElementStepper,
104
+ FlexElementSpacer,
105
+ // Speaker Notes
106
+ SpeakerSyncPayload,
107
+ // Theme Types (NEW)
108
+ ThemeColors,
109
+ ThemeTypography,
110
+ ThemeSpacing,
111
+ ThemeBorderRadius,
112
+ ThemeEffects,
113
+ ThemeComponents,
114
+ } from './core/types';
115
+
116
+ // Events
117
+ export { bus, EventBus, type Handler } from './core/events';
118
+
119
+ // Speaker Notes
120
+ export { SpeakerChannel, type MessageHandler } from './core/speaker-channel';
121
+
122
+ // Theme System (NEW)
123
+ export { ThemeManager, DEFAULT_THEME } from './core/theme';
124
+ export { THEME_PRESETS } from './core/presets';
125
+ export { getLuminaJsonSchema, getThemeJsonSchema, ThemeConfigSchema } from './core/schema';
126
+
127
+ // Prompt Generation
128
+ export { generateSystemPrompt, generateThemePrompt, type SystemPromptOptions } from './core/prompts';
129
+
130
+ // Streaming (for LLM token streams and partial JSON)
131
+ export { parsePartialJson, createDebouncedLoader, isSlideReady } from './utils/streaming';
132
+
133
+ // Animation config: centralized defaults and resolution (options / meta.effects / slide.meta.effects)
134
+ export { resolveTransitionConfig, ANIMATION_DEFAULTS, type ResolvedTransitionConfig } from './core/animationConfig';
135
+
136
+ // Animation: presets, stagger, resolver (ANIMATION_IDEAS.md, ANIMATION_STRATEGY.md)
137
+ export {
138
+ BUILTIN_PRESETS,
139
+ getPreset,
140
+ registerPreset,
141
+ resolveAnimationFromInput,
142
+ computeStagger,
143
+ type StaggerMode,
144
+ type StaggerOptions,
145
+ type StaggerStep,
146
+ type PresetDef,
147
+ } from './animation';
148
+
149
+ // Element control: resolution and discovery (for engine.element(id), engine.element(slideIndex, path), engine.elements(slideIndex))
150
+ export { elemId } from './core/elementId';
151
+ export {
152
+ resolveId,
153
+ parsePath,
154
+ pathToKey,
155
+ getElementPaths,
156
+ getElementIds,
157
+ registerElementPaths,
158
+ type ElementPath,
159
+ type PathGenerator
160
+ } from './core/elementResolver';
161
+
162
+ export type {
163
+ ElementState,
164
+ ElementController,
165
+ AnimateOptions,
166
+ RevealInSequenceOptions,
167
+ InitialElementState,
168
+ TimelineKeyframes,
169
+ TimelineKeyframeState,
170
+ TimelineTracks,
171
+ } from './core/types';
172
+
173
+ export { default as LuminaDeck } from './components/LuminaDeck.vue';
174
+ export { default as LuminaStudio } from './components/studio/LuminaStudio.vue';
175
+ import './style/main.css';
package/src/main.ts ADDED
@@ -0,0 +1,17 @@
1
+ import { createApp } from 'vue'
2
+ import App from './App.vue'
3
+ import './style/main.css'
4
+ import { initFirebase } from './utils/firebase'
5
+
6
+ // Initialize Infrastructure
7
+ try {
8
+ initFirebase();
9
+ } catch (e) {
10
+ console.error("Failed to initialize Firebase:", e);
11
+ }
12
+
13
+ import router from './router'
14
+
15
+ const app = createApp(App)
16
+ app.use(router)
17
+ app.mount('#app')
@@ -0,0 +1,92 @@
1
+ import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
2
+ import { getFirebaseAuth } from '../utils/firebase';
3
+
4
+ const routes: RouteRecordRaw[] = [
5
+ {
6
+ path: '/',
7
+ component: () => import('../views/SiteLayout.vue'),
8
+ children: [
9
+ {
10
+ path: '',
11
+ name: 'home',
12
+ component: () => import('../components/site/SiteHome.vue')
13
+ },
14
+ {
15
+ path: 'dashboard',
16
+ name: 'dashboard',
17
+ component: () => import('../components/site/SiteDashboard.vue'),
18
+ meta: { requiresAuth: true }
19
+ },
20
+ {
21
+ path: 'examples',
22
+ name: 'examples',
23
+ component: () => import('../components/site/SiteExamples.vue')
24
+ },
25
+ {
26
+ path: 'docs',
27
+ name: 'docs',
28
+ component: () => import('../components/site/SiteDocs.vue')
29
+ },
30
+ {
31
+ path: 'playground',
32
+ name: 'playground',
33
+ component: () => import('../components/site/SitePlayground.vue')
34
+ },
35
+ {
36
+ path: 'prompt-builder',
37
+ name: 'prompt-builder',
38
+ component: () => import('../components/site/SitePromptBuilder.vue')
39
+ },
40
+ {
41
+ path: 'api',
42
+ name: 'api',
43
+ component: () => import('../components/site/SiteApi.vue')
44
+ }
45
+ ]
46
+ },
47
+ {
48
+ path: '/studio/:id?',
49
+ name: 'studio',
50
+ component: () => import('../views/StudioView.vue'),
51
+ meta: { requiresAuth: true }
52
+ },
53
+ {
54
+ path: '/deck/:id',
55
+ name: 'deck',
56
+ component: () => import('../views/DeckView.vue')
57
+ }
58
+ ];
59
+
60
+ const router = createRouter({
61
+ history: createWebHistory(import.meta.env.BASE_URL),
62
+ routes,
63
+ scrollBehavior(_to, _from, savedPosition) {
64
+ if (savedPosition) {
65
+ return savedPosition;
66
+ }
67
+ return { top: 0 };
68
+ }
69
+ });
70
+
71
+ // Navigation Guard
72
+ router.beforeEach(async (to, _from, next) => {
73
+ const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
74
+
75
+ // Simple check - in a real app wait for auth init
76
+ if (requiresAuth) {
77
+ try {
78
+ const auth = getFirebaseAuth();
79
+ if (!auth.currentUser) {
80
+ // If not logged in, redirect home or show login
81
+ // For now, we allow access but components might handle logic,
82
+ // or we could redirect to home with a query param
83
+ // next({ name: 'home' });
84
+ }
85
+ } catch (e) {
86
+ // Auth not initialized yet, proceed (components handle it)
87
+ }
88
+ }
89
+ next();
90
+ });
91
+
92
+ export default router;