@vibecuting/video-project-core 0.1.29 → 0.1.31

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 (182) hide show
  1. package/package.json +9 -5
  2. package/src/base/BaseRemotionScene.test.tsx +11 -1
  3. package/src/base/index.ts +1 -0
  4. package/src/base/utils/asset-source.ts +11 -0
  5. package/src/base/utils/background-audio-layer.tsx +90 -0
  6. package/src/base/utils/background-layer.tsx +84 -0
  7. package/src/base/utils/chapter-progress-foreground.tsx +125 -0
  8. package/src/base/utils/chapter-progress-state.test.ts +28 -0
  9. package/src/base/utils/chapter-progress-state.ts +33 -0
  10. package/src/base/utils/display-motion.test.ts +21 -0
  11. package/src/base/utils/display-motion.ts +52 -0
  12. package/src/base/utils/display-surface.ts +57 -0
  13. package/src/base/utils/index.ts +10 -0
  14. package/src/base/utils/subtitle-style.ts +28 -0
  15. package/src/base/utils/video-layer-types.test.ts +145 -0
  16. package/src/base/utils/video-layer-types.ts +220 -0
  17. package/src/base/utils/voice-captions-foreground.tsx +169 -0
  18. package/src/core/intro/index.ts +18 -18
  19. package/src/core/outro/index.ts +33 -33
  20. package/src/core/scene/2dscene/{default-2d-scene-Horizontal.stories.tsx → default-2d-scene/default-2d-scene-Horizontal.stories.tsx} +1 -1
  21. package/src/core/scene/2dscene/{default-2d-scene-Horizontal.tsx → default-2d-scene/default-2d-scene-Horizontal.tsx} +1 -1
  22. package/src/core/scene/2dscene/{default-2d-scene-Landscape.tsx → default-2d-scene/default-2d-scene-Landscape.tsx} +1 -1
  23. package/src/core/scene/2dscene/{default-2d-scene.stories.tsx → default-2d-scene/default-2d-scene.stories.tsx} +1 -1
  24. package/src/core/scene/2dscene/{default-2d-scene.tsx → default-2d-scene/default-2d-scene.tsx} +4 -4
  25. package/src/core/scene/2dscene/index.ts +3 -3
  26. package/src/core/scene/3dscene/{default-3d-scene-Horizontal.stories.tsx → default-3d-scene/default-3d-scene-Horizontal.stories.tsx} +1 -1
  27. package/src/core/scene/3dscene/{default-3d-scene-Horizontal.tsx → default-3d-scene/default-3d-scene-Horizontal.tsx} +1 -1
  28. package/src/core/scene/3dscene/{default-3d-scene-Landscape.tsx → default-3d-scene/default-3d-scene-Landscape.tsx} +1 -1
  29. package/src/core/scene/3dscene/{default-3d-scene.stories.tsx → default-3d-scene/default-3d-scene.stories.tsx} +1 -1
  30. package/src/core/scene/3dscene/{default-3d-scene.tsx → default-3d-scene/default-3d-scene.tsx} +4 -4
  31. package/src/core/scene/3dscene/index.ts +3 -3
  32. package/src/core/scene/html-in-canvas/browser/default-html-in-canvas-browser-scene-Horizontal.stories.tsx +35 -0
  33. package/src/core/scene/html-in-canvas/browser/default-html-in-canvas-browser-scene-Landscape.stories.tsx +80 -0
  34. package/src/core/scene/html-in-canvas/dashboard/default-html-in-canvas-dashboard-scene-Horizontal.stories.tsx +35 -0
  35. package/src/core/scene/html-in-canvas/dashboard/default-html-in-canvas-dashboard-scene-Landscape.stories.tsx +35 -0
  36. package/src/core/scene/html-in-canvas/dashboard-shell/default-dashboard-shell-html-in-canvas-scene.stories.tsx +40 -0
  37. package/src/core/scene/html-in-canvas/dashboard-shell/default-dashboard-shell-html-in-canvas-scene.tsx +44 -0
  38. package/src/core/scene/html-in-canvas/dashboard-shell/index.ts +8 -0
  39. package/src/core/scene/html-in-canvas/docs/default-html-in-canvas-docs-scene-Horizontal.stories.tsx +35 -0
  40. package/src/core/scene/html-in-canvas/docs/default-html-in-canvas-docs-scene-Landscape.stories.tsx +35 -0
  41. package/src/core/scene/html-in-canvas/document/article/default-article-html-in-canvas-scene.stories.tsx +38 -0
  42. package/src/core/scene/html-in-canvas/document/article/default-article-html-in-canvas-scene.tsx +50 -0
  43. package/src/core/scene/html-in-canvas/document/article/index.ts +8 -0
  44. package/src/core/scene/html-in-canvas/document/default-document-html-in-canvas-scene.stories.tsx +40 -0
  45. package/src/core/scene/html-in-canvas/document/default-document-html-in-canvas-scene.tsx +50 -0
  46. package/src/core/scene/html-in-canvas/document/index.ts +31 -0
  47. package/src/core/scene/html-in-canvas/document/report/default-report-html-in-canvas-scene.stories.tsx +38 -0
  48. package/src/core/scene/html-in-canvas/document/report/default-report-html-in-canvas-scene.tsx +51 -0
  49. package/src/core/scene/html-in-canvas/document/report/index.ts +8 -0
  50. package/src/core/scene/html-in-canvas/document/whitepaper/default-whitepaper-html-in-canvas-scene.stories.tsx +41 -0
  51. package/src/core/scene/html-in-canvas/document/whitepaper/default-whitepaper-html-in-canvas-scene.tsx +50 -0
  52. package/src/core/scene/html-in-canvas/document/whitepaper/index.ts +8 -0
  53. package/src/core/scene/html-in-canvas/editor/default-html-in-canvas-editor-scene-Horizontal.stories.tsx +35 -0
  54. package/src/core/scene/html-in-canvas/editor/default-html-in-canvas-editor-scene-Landscape.stories.tsx +35 -0
  55. package/src/core/scene/html-in-canvas/full-bleed/default-full-bleed-html-in-canvas-scene.stories.tsx +40 -0
  56. package/src/core/scene/html-in-canvas/full-bleed/default-full-bleed-html-in-canvas-scene.tsx +38 -0
  57. package/src/core/scene/html-in-canvas/full-bleed/index.ts +8 -0
  58. package/src/core/scene/html-in-canvas/index.ts +6 -0
  59. package/src/core/scene/html-in-canvas/landing-page/default-landing-page-html-in-canvas-scene.stories.tsx +40 -0
  60. package/src/core/scene/html-in-canvas/landing-page/default-landing-page-html-in-canvas-scene.tsx +46 -0
  61. package/src/core/scene/html-in-canvas/landing-page/feature-grid/default-feature-grid-html-in-canvas-scene.stories.tsx +38 -0
  62. package/src/core/scene/html-in-canvas/landing-page/feature-grid/default-feature-grid-html-in-canvas-scene.tsx +41 -0
  63. package/src/core/scene/html-in-canvas/landing-page/feature-grid/index.ts +8 -0
  64. package/src/core/scene/html-in-canvas/landing-page/hero/default-hero-html-in-canvas-scene.stories.tsx +38 -0
  65. package/src/core/scene/html-in-canvas/landing-page/hero/default-hero-html-in-canvas-scene.tsx +46 -0
  66. package/src/core/scene/html-in-canvas/landing-page/hero/index.ts +8 -0
  67. package/src/core/scene/html-in-canvas/landing-page/index.ts +31 -0
  68. package/src/core/scene/html-in-canvas/landing-page/pricing/default-pricing-html-in-canvas-scene.stories.tsx +38 -0
  69. package/src/core/scene/html-in-canvas/landing-page/pricing/default-pricing-html-in-canvas-scene.tsx +42 -0
  70. package/src/core/scene/html-in-canvas/landing-page/pricing/index.ts +8 -0
  71. package/src/core/scene/html-in-canvas/media-wall/collage/default-collage-html-in-canvas-scene.stories.tsx +38 -0
  72. package/src/core/scene/html-in-canvas/media-wall/collage/default-collage-html-in-canvas-scene.tsx +42 -0
  73. package/src/core/scene/html-in-canvas/media-wall/collage/index.ts +8 -0
  74. package/src/core/scene/html-in-canvas/media-wall/default-media-wall-html-in-canvas-scene.stories.tsx +40 -0
  75. package/src/core/scene/html-in-canvas/media-wall/default-media-wall-html-in-canvas-scene.tsx +35 -0
  76. package/src/core/scene/html-in-canvas/media-wall/gallery/default-gallery-html-in-canvas-scene.stories.tsx +38 -0
  77. package/src/core/scene/html-in-canvas/media-wall/gallery/default-gallery-html-in-canvas-scene.tsx +43 -0
  78. package/src/core/scene/html-in-canvas/media-wall/gallery/index.ts +8 -0
  79. package/src/core/scene/html-in-canvas/media-wall/grid/default-grid-html-in-canvas-scene.stories.tsx +38 -0
  80. package/src/core/scene/html-in-canvas/media-wall/grid/default-grid-html-in-canvas-scene.tsx +35 -0
  81. package/src/core/scene/html-in-canvas/media-wall/grid/index.ts +8 -0
  82. package/src/core/scene/html-in-canvas/media-wall/index.ts +31 -0
  83. package/src/core/scene/html-in-canvas/shared/default-html-in-canvas-scene.tsx +1315 -0
  84. package/src/core/scene/index.ts +1 -0
  85. package/src/core/scene/photo/3dvr-photo/{default-3dvr-photo-scene.stories.tsx → default-3dvr-photo-scene/default-3dvr-photo-scene.stories.tsx} +2 -2
  86. package/src/core/scene/photo/3dvr-photo/{default-3dvr-photo-scene.tsx → default-3dvr-photo-scene/default-3dvr-photo-scene.tsx} +4 -4
  87. package/src/core/scene/photo/3dvr-photo/{default-3dvr-photo-scene-Horizontal.stories.tsx → default-3dvr-photo-scene-Horizontal/default-3dvr-photo-scene-Horizontal.stories.tsx} +1 -1
  88. package/src/core/scene/photo/3dvr-photo/{default-3dvr-photo-scene-Horizontal.tsx → default-3dvr-photo-scene-Horizontal/default-3dvr-photo-scene-Horizontal.tsx} +4 -4
  89. package/src/core/scene/photo/3dvr-photo/{default-3dvr-photo-scene-Landscape.tsx → default-3dvr-photo-scene-Landscape/default-3dvr-photo-scene-Landscape.tsx} +4 -4
  90. package/src/core/scene/photo/3dvr-photo/default-dolly-3dvr-photo-scene/default-dolly-3dvr-photo-scene.stories.tsx +38 -0
  91. package/src/core/scene/photo/3dvr-photo/default-dolly-3dvr-photo-scene/default-dolly-3dvr-photo-scene.tsx +36 -0
  92. package/src/core/scene/photo/3dvr-photo/default-orbit-3dvr-photo-scene/default-orbit-3dvr-photo-scene.stories.tsx +38 -0
  93. package/src/core/scene/photo/3dvr-photo/default-orbit-3dvr-photo-scene/default-orbit-3dvr-photo-scene.tsx +34 -0
  94. package/src/core/scene/photo/3dvr-photo/default-poster-3dvr-photo-scene/default-poster-3dvr-photo-scene.stories.tsx +38 -0
  95. package/src/core/scene/photo/3dvr-photo/default-poster-3dvr-photo-scene/default-poster-3dvr-photo-scene.tsx +39 -0
  96. package/src/core/scene/photo/3dvr-photo/index.ts +6 -3
  97. package/src/core/scene/photo/effects-photo/default-chrome-effects-photo-scene/default-chrome-effects-photo-scene.stories.tsx +24 -0
  98. package/src/core/scene/photo/effects-photo/default-chrome-effects-photo-scene/default-chrome-effects-photo-scene.tsx +39 -0
  99. package/src/core/scene/photo/effects-photo/default-cool-tone-effects-photo-scene/default-cool-tone-effects-photo-scene.stories.tsx +24 -0
  100. package/src/core/scene/photo/effects-photo/default-cool-tone-effects-photo-scene/default-cool-tone-effects-photo-scene.tsx +39 -0
  101. package/src/core/scene/photo/effects-photo/default-dream-effects-photo-scene/default-dream-effects-photo-scene.stories.tsx +23 -0
  102. package/src/core/scene/photo/effects-photo/default-dream-effects-photo-scene/default-dream-effects-photo-scene.tsx +37 -0
  103. package/src/core/scene/photo/effects-photo/default-duotone-effects-photo-scene/default-duotone-effects-photo-scene.stories.tsx +25 -0
  104. package/src/core/scene/photo/effects-photo/default-duotone-effects-photo-scene/default-duotone-effects-photo-scene.tsx +41 -0
  105. package/src/core/scene/photo/effects-photo/{default-effects-photo-scene.stories.tsx → default-effects-photo-scene/default-effects-photo-scene.stories.tsx} +2 -2
  106. package/src/core/scene/photo/effects-photo/default-effects-photo-scene/default-effects-photo-scene.tsx +639 -0
  107. package/src/core/scene/photo/effects-photo/{default-effects-photo-scene-Horizontal.stories.tsx → default-effects-photo-scene-Horizontal/default-effects-photo-scene-Horizontal.stories.tsx} +1 -1
  108. package/src/core/scene/photo/effects-photo/{default-effects-photo-scene-Horizontal.tsx → default-effects-photo-scene-Horizontal/default-effects-photo-scene-Horizontal.tsx} +4 -4
  109. package/src/core/scene/photo/effects-photo/{default-effects-photo-scene-Landscape.tsx → default-effects-photo-scene-Landscape/default-effects-photo-scene-Landscape.tsx} +4 -4
  110. package/src/core/scene/photo/effects-photo/default-glow-effects-photo-scene/default-glow-effects-photo-scene.stories.tsx +39 -0
  111. package/src/core/scene/photo/effects-photo/default-glow-effects-photo-scene/default-glow-effects-photo-scene.tsx +37 -0
  112. package/src/core/scene/photo/effects-photo/default-grain-effects-photo-scene/default-grain-effects-photo-scene.stories.tsx +39 -0
  113. package/src/core/scene/photo/effects-photo/default-grain-effects-photo-scene/default-grain-effects-photo-scene.tsx +37 -0
  114. package/src/core/scene/photo/effects-photo/default-halation-effects-photo-scene/default-halation-effects-photo-scene.stories.tsx +24 -0
  115. package/src/core/scene/photo/effects-photo/default-halation-effects-photo-scene/default-halation-effects-photo-scene.tsx +39 -0
  116. package/src/core/scene/photo/effects-photo/default-infrared-effects-photo-scene/default-infrared-effects-photo-scene.stories.tsx +24 -0
  117. package/src/core/scene/photo/effects-photo/default-infrared-effects-photo-scene/default-infrared-effects-photo-scene.tsx +39 -0
  118. package/src/core/scene/photo/effects-photo/default-light-leak-effects-photo-scene/default-light-leak-effects-photo-scene.stories.tsx +24 -0
  119. package/src/core/scene/photo/effects-photo/default-light-leak-effects-photo-scene/default-light-leak-effects-photo-scene.tsx +39 -0
  120. package/src/core/scene/photo/effects-photo/default-mono-effects-photo-scene/default-mono-effects-photo-scene.stories.tsx +23 -0
  121. package/src/core/scene/photo/effects-photo/default-mono-effects-photo-scene/default-mono-effects-photo-scene.tsx +37 -0
  122. package/src/core/scene/photo/effects-photo/default-noir-effects-photo-scene/default-noir-effects-photo-scene.stories.tsx +23 -0
  123. package/src/core/scene/photo/effects-photo/default-noir-effects-photo-scene/default-noir-effects-photo-scene.tsx +37 -0
  124. package/src/core/scene/photo/effects-photo/default-pastel-effects-photo-scene/default-pastel-effects-photo-scene.stories.tsx +24 -0
  125. package/src/core/scene/photo/effects-photo/default-pastel-effects-photo-scene/default-pastel-effects-photo-scene.tsx +39 -0
  126. package/src/core/scene/photo/effects-photo/default-retro-effects-photo-scene/default-retro-effects-photo-scene.stories.tsx +24 -0
  127. package/src/core/scene/photo/effects-photo/default-retro-effects-photo-scene/default-retro-effects-photo-scene.tsx +39 -0
  128. package/src/core/scene/photo/effects-photo/default-sepia-effects-photo-scene/default-sepia-effects-photo-scene.stories.tsx +23 -0
  129. package/src/core/scene/photo/effects-photo/default-sepia-effects-photo-scene/default-sepia-effects-photo-scene.tsx +37 -0
  130. package/src/core/scene/photo/effects-photo/default-soft-focus-effects-photo-scene/default-soft-focus-effects-photo-scene.stories.tsx +39 -0
  131. package/src/core/scene/photo/effects-photo/default-soft-focus-effects-photo-scene/default-soft-focus-effects-photo-scene.tsx +37 -0
  132. package/src/core/scene/photo/effects-photo/default-vibrant-effects-photo-scene/default-vibrant-effects-photo-scene.stories.tsx +23 -0
  133. package/src/core/scene/photo/effects-photo/default-vibrant-effects-photo-scene/default-vibrant-effects-photo-scene.tsx +37 -0
  134. package/src/core/scene/photo/effects-photo/default-vignette-effects-photo-scene/default-vignette-effects-photo-scene.stories.tsx +39 -0
  135. package/src/core/scene/photo/effects-photo/default-vignette-effects-photo-scene/default-vignette-effects-photo-scene.tsx +37 -0
  136. package/src/core/scene/photo/effects-photo/default-warmth-effects-photo-scene/default-warmth-effects-photo-scene.stories.tsx +40 -0
  137. package/src/core/scene/photo/effects-photo/default-warmth-effects-photo-scene/default-warmth-effects-photo-scene.tsx +39 -0
  138. package/src/core/scene/photo/effects-photo/index.ts +21 -3
  139. package/src/core/scene/photo/index.ts +25 -9
  140. package/src/core/scene/photo/{default-live-photo-scene-Horizontal.stories.tsx → live-photo/default-live-photo-scene-Horizontal.stories.tsx} +1 -1
  141. package/src/core/scene/photo/{default-live-photo-scene-Horizontal.tsx → live-photo/default-live-photo-scene-Horizontal.tsx} +1 -1
  142. package/src/core/scene/photo/{default-live-photo-scene-Landscape.tsx → live-photo/default-live-photo-scene-Landscape.tsx} +1 -1
  143. package/src/core/scene/photo/{default-live-photo-scene.stories.tsx → live-photo/default-live-photo-scene.stories.tsx} +1 -1
  144. package/src/core/scene/photo/{default-live-photo-scene.tsx → live-photo/default-live-photo-scene.tsx} +5 -3
  145. package/src/core/scene/photo/photo-storybook.test.tsx +2 -2
  146. package/src/core/scene/photo/{default-photo-strip-scene-Horizontal.tsx → photo-strip/default-photo-strip-scene-Horizontal.tsx} +1 -1
  147. package/src/core/scene/photo/{default-photo-strip-scene-Landscape.tsx → photo-strip/default-photo-strip-scene-Landscape.tsx} +1 -1
  148. package/src/core/scene/photo/{default-photo-strip-scene.stories.tsx → photo-strip/default-photo-strip-scene.stories.tsx} +1 -1
  149. package/src/core/scene/photo/{default-photo-strip-scene.tsx → photo-strip/default-photo-strip-scene.tsx} +2 -2
  150. package/src/core/scene/photo/{default-photo-wall-scene-Horizontal.tsx → photo-wall/default-photo-wall-scene-Horizontal.tsx} +1 -1
  151. package/src/core/scene/photo/{default-photo-wall-scene-Landscape.tsx → photo-wall/default-photo-wall-scene-Landscape.tsx} +1 -1
  152. package/src/core/scene/photo/{default-photo-wall-scene.stories.tsx → photo-wall/default-photo-wall-scene.stories.tsx} +1 -1
  153. package/src/core/scene/photo/{default-photo-wall-scene.tsx → photo-wall/default-photo-wall-scene.tsx} +2 -2
  154. package/src/core/scene/slide/{default-slide-scene-Horizontal.animated.stories.tsx → default-slide-scene/default-slide-scene-Horizontal.animated.stories.tsx} +1 -1
  155. package/src/core/scene/slide/{default-slide-scene-Horizontal.tsx → default-slide-scene/default-slide-scene-Horizontal.tsx} +1 -1
  156. package/src/core/scene/slide/{default-slide-scene-Landscape.tsx → default-slide-scene/default-slide-scene-Landscape.tsx} +1 -1
  157. package/src/core/scene/slide/{default-slide-scene.animated.stories.tsx → default-slide-scene/default-slide-scene.animated.stories.tsx} +1 -1
  158. package/src/core/scene/slide/{default-slide-scene.tsx → default-slide-scene/default-slide-scene.tsx} +5 -5
  159. package/src/core/scene/slide/index.ts +3 -3
  160. package/src/core/scene/video/{default-video-scene-Horizontal.stories.tsx → default-video-scene/default-video-scene-Horizontal.stories.tsx} +1 -1
  161. package/src/core/scene/video/{default-video-scene-Horizontal.tsx → default-video-scene/default-video-scene-Horizontal.tsx} +1 -1
  162. package/src/core/scene/video/{default-video-scene-Landscape.tsx → default-video-scene/default-video-scene-Landscape.tsx} +1 -1
  163. package/src/core/scene/video/{default-video-scene.stories.tsx → default-video-scene/default-video-scene.stories.tsx} +1 -1
  164. package/src/core/scene/video/{default-video-scene.tsx → default-video-scene/default-video-scene.tsx} +3 -3
  165. package/src/core/scene/video/{default-video-split-scene-Horizontal.tsx → default-video-split-scene/default-video-split-scene-Horizontal.tsx} +1 -1
  166. package/src/core/scene/video/{default-video-split-scene-Landscape.tsx → default-video-split-scene/default-video-split-scene-Landscape.tsx} +1 -1
  167. package/src/core/scene/video/{default-video-split-scene.stories.tsx → default-video-split-scene/default-video-split-scene.stories.tsx} +1 -1
  168. package/src/core/scene/video/{default-video-split-scene.tsx → default-video-split-scene/default-video-split-scene.tsx} +2 -2
  169. package/src/core/scene/video/{default-video-wall-scene-Horizontal.tsx → default-video-wall-scene/default-video-wall-scene-Horizontal.tsx} +1 -1
  170. package/src/core/scene/video/{default-video-wall-scene-Landscape.tsx → default-video-wall-scene/default-video-wall-scene-Landscape.tsx} +1 -1
  171. package/src/core/scene/video/{default-video-wall-scene.stories.tsx → default-video-wall-scene/default-video-wall-scene.stories.tsx} +1 -1
  172. package/src/core/scene/video/{default-video-wall-scene.tsx → default-video-wall-scene/default-video-wall-scene.tsx} +2 -2
  173. package/src/core/scene/video/index.ts +9 -9
  174. package/src/lint/index.ts +2 -0
  175. package/src/lint/scene-convention-lint.test.ts +86 -0
  176. package/src/lint/scene-convention-lint.ts +247 -0
  177. package/src/storybook/index.ts +19 -0
  178. package/src/storybook/remotion-preview.test.tsx +53 -0
  179. package/src/storybook/remotion-preview.tsx +85 -11
  180. package/src/core/scene/photo/effects-photo/default-effects-photo-scene.tsx +0 -352
  181. /package/src/core/scene/slide/{default-slide-scene-Horizontal.stories.tsx → default-slide-scene/default-slide-scene-Horizontal.stories.tsx} +0 -0
  182. /package/src/core/scene/slide/{default-slide-scene.stories.tsx → default-slide-scene/default-slide-scene.stories.tsx} +0 -0
@@ -0,0 +1,1315 @@
1
+ import type { ReactNode } from 'react'
2
+ import { z } from 'zod'
3
+
4
+ import { VideoComponent, defineScenePluginMetadata } from '@vibecuting/component-project-helper'
5
+ import { HtmlInCanvas, spring, useCurrentFrame, useVideoConfig } from 'remotion'
6
+
7
+ import { BaseRemotionScene, type BaseRemotionSceneProps, useRemotionSceneRuntime, useSceneConfig } from '../../../../base'
8
+ import { defineSceneComponent } from '../../../../plugins/scene-component'
9
+
10
+ type HtmlCanvasTemplate = 'browser' | 'dashboard' | 'editor' | 'docs'
11
+
12
+ export interface DefaultHtmlInCanvasSceneProps extends BaseRemotionSceneProps {
13
+ sceneId?: string
14
+ sceneName?: string
15
+ title?: string
16
+ subtitle?: string
17
+ badge?: string
18
+ accent?: string
19
+ secondaryAccent?: string
20
+ textColor?: string
21
+ html?: string
22
+ }
23
+
24
+ type HtmlCanvasSceneConfig = {
25
+ name: string
26
+ description: string
27
+ sourceFile: string
28
+ pluginKey: string
29
+ aspectRatio: '16:9' | '9:16'
30
+ template: HtmlCanvasTemplate
31
+ }
32
+
33
+ export function HtmlCanvasSurface({
34
+ width,
35
+ height,
36
+ children,
37
+ theme,
38
+ }: {
39
+ width: number
40
+ height: number
41
+ children: ReactNode
42
+ theme: string
43
+ }) {
44
+ if (!HtmlInCanvas.isSupported()) {
45
+ return (
46
+ <div
47
+ style={{
48
+ position: 'absolute',
49
+ inset: 0,
50
+ overflow: 'hidden',
51
+ background: theme,
52
+ }}
53
+ >
54
+ {children}
55
+ </div>
56
+ )
57
+ }
58
+
59
+ return (
60
+ <HtmlInCanvas
61
+ width={width}
62
+ height={height}
63
+ durationInFrames={150}
64
+ pixelDensity={2}
65
+ style={{
66
+ position: 'absolute',
67
+ inset: 0,
68
+ overflow: 'hidden',
69
+ background: theme,
70
+ }}
71
+ >
72
+ {children}
73
+ </HtmlInCanvas>
74
+ )
75
+ }
76
+
77
+ export function HtmlMarkupSurface({
78
+ width,
79
+ height,
80
+ html,
81
+ theme,
82
+ }: {
83
+ width: number
84
+ height: number
85
+ html: string
86
+ theme: string
87
+ }) {
88
+ const markup = html.trim()
89
+ const content = (
90
+ <div
91
+ style={{
92
+ position: 'absolute',
93
+ inset: 0,
94
+ overflow: 'hidden',
95
+ background: theme,
96
+ }}
97
+ >
98
+ <style>{`
99
+ .html-canvas-root,
100
+ .html-canvas-root * {
101
+ box-sizing: border-box;
102
+ }
103
+
104
+ .html-canvas-root {
105
+ width: 100%;
106
+ height: 100%;
107
+ min-width: 0;
108
+ min-height: 0;
109
+ overflow: hidden;
110
+ }
111
+
112
+ .html-canvas-root > * {
113
+ width: 100%;
114
+ height: 100%;
115
+ min-width: 0;
116
+ min-height: 0;
117
+ }
118
+
119
+ .html-canvas-root :where(img, video, canvas, svg, picture, iframe) {
120
+ display: block;
121
+ max-width: 100%;
122
+ max-height: 100%;
123
+ }
124
+
125
+ .html-canvas-root :where(img, video) {
126
+ object-fit: cover;
127
+ }
128
+
129
+ .html-canvas-root :where(p, h1, h2, h3, h4, h5, h6, ul, ol, dl, blockquote) {
130
+ margin-block-start: 0;
131
+ margin-block-end: 0;
132
+ }
133
+ `}</style>
134
+ <div className="html-canvas-root" dangerouslySetInnerHTML={{ __html: markup }} />
135
+ </div>
136
+ )
137
+
138
+ if (!HtmlInCanvas.isSupported()) {
139
+ return content
140
+ }
141
+
142
+ return (
143
+ <HtmlInCanvas
144
+ width={width}
145
+ height={height}
146
+ durationInFrames={150}
147
+ pixelDensity={2}
148
+ style={{
149
+ position: 'absolute',
150
+ inset: 0,
151
+ overflow: 'hidden',
152
+ background: theme,
153
+ }}
154
+ >
155
+ {content}
156
+ </HtmlInCanvas>
157
+ )
158
+ }
159
+
160
+ function TemplateBadge({
161
+ label,
162
+ accent,
163
+ }: {
164
+ label: string
165
+ accent: string
166
+ }) {
167
+ return (
168
+ <div
169
+ style={{
170
+ display: 'inline-flex',
171
+ alignItems: 'center',
172
+ gap: 8,
173
+ padding: '8px 12px',
174
+ border: '1px solid rgba(255,255,255,0.18)',
175
+ background: 'rgba(2,6,23,0.55)',
176
+ color: '#f8fafc',
177
+ textTransform: 'uppercase',
178
+ letterSpacing: '0.2em',
179
+ fontSize: 11,
180
+ lineHeight: 1,
181
+ }}
182
+ >
183
+ <span
184
+ aria-hidden="true"
185
+ style={{
186
+ width: 8,
187
+ height: 8,
188
+ borderRadius: 9999,
189
+ background: accent,
190
+ boxShadow: `0 0 0 4px ${accent}22`,
191
+ }}
192
+ />
193
+ {label}
194
+ </div>
195
+ )
196
+ }
197
+
198
+ function BrowserTemplate({
199
+ title,
200
+ subtitle,
201
+ badge,
202
+ accent = '#2563eb',
203
+ secondaryAccent = '#0f172a',
204
+ runtimeWidth,
205
+ runtimeHeight,
206
+ progress,
207
+ sceneType,
208
+ }: {
209
+ title: string
210
+ subtitle?: string
211
+ badge: string
212
+ accent?: string
213
+ secondaryAccent?: string
214
+ runtimeWidth: number
215
+ runtimeHeight: number
216
+ progress: number
217
+ sceneType: 'static' | 'animation'
218
+ }) {
219
+ const portrait = runtimeHeight > runtimeWidth
220
+ const featureScale = 1 + (sceneType === 'animation' ? progress * 0.015 : 0)
221
+
222
+ return (
223
+ <div
224
+ style={{
225
+ width: '100%',
226
+ height: '100%',
227
+ display: 'grid',
228
+ gridTemplateRows: 'auto 1fr',
229
+ color: '#e2e8f0',
230
+ background:
231
+ 'radial-gradient(circle at 18% 20%, rgba(59,130,246,0.22) 0%, rgba(2,6,23,0.04) 34%, rgba(2,6,23,0.08) 100%), linear-gradient(180deg, #f8fafc 0%, #e2e8f0 100%)',
232
+ }}
233
+ >
234
+ <div
235
+ style={{
236
+ display: 'flex',
237
+ alignItems: 'center',
238
+ justifyContent: 'space-between',
239
+ gap: 16,
240
+ padding: portrait ? '12px 14px' : '16px 20px',
241
+ background: 'rgba(15,23,42,0.96)',
242
+ borderBottom: '1px solid rgba(255,255,255,0.08)',
243
+ }}
244
+ >
245
+ <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
246
+ <span style={{ width: 10, height: 10, borderRadius: 9999, background: '#ef4444' }} />
247
+ <span style={{ width: 10, height: 10, borderRadius: 9999, background: '#f59e0b' }} />
248
+ <span style={{ width: 10, height: 10, borderRadius: 9999, background: '#22c55e' }} />
249
+ </div>
250
+ <div
251
+ style={{
252
+ flex: 1,
253
+ marginInline: 16,
254
+ padding: '10px 14px',
255
+ border: '1px solid rgba(255,255,255,0.12)',
256
+ borderRadius: 0,
257
+ background: 'rgba(2,6,23,0.72)',
258
+ color: '#cbd5e1',
259
+ fontSize: portrait ? 12 : 13,
260
+ letterSpacing: '0.04em',
261
+ overflow: 'hidden',
262
+ whiteSpace: 'nowrap',
263
+ textOverflow: 'ellipsis',
264
+ }}
265
+ >
266
+ https://canvas.vibecuting.local/{badge.toLowerCase().replace(/\s+/g, '-')}
267
+ </div>
268
+ <TemplateBadge label={badge} accent={accent} />
269
+ </div>
270
+
271
+ <div
272
+ style={{
273
+ position: 'relative',
274
+ padding: portrait ? 16 : 22,
275
+ display: 'grid',
276
+ gridTemplateColumns: portrait ? '1fr' : '1.1fr 0.9fr',
277
+ gap: portrait ? 16 : 20,
278
+ minWidth: 0,
279
+ minHeight: 0,
280
+ }}
281
+ >
282
+ <div
283
+ style={{
284
+ display: 'grid',
285
+ gap: 16,
286
+ alignContent: 'start',
287
+ minWidth: 0,
288
+ }}
289
+ >
290
+ <div
291
+ style={{
292
+ padding: portrait ? 18 : 22,
293
+ border: '1px solid rgba(15,23,42,0.12)',
294
+ background: 'rgba(255,255,255,0.82)',
295
+ boxShadow: '0 20px 80px rgba(15,23,42,0.08)',
296
+ transform: `translate3d(0, ${(1 - progress) * 8}px, 0) scale(${featureScale})`,
297
+ transformOrigin: 'center center',
298
+ }}
299
+ >
300
+ <div style={{ display: 'grid', gap: 12, maxWidth: portrait ? '100%' : '88%' }}>
301
+ <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
302
+ <TemplateBadge label="Html in Canvas" accent={accent} />
303
+ <span style={{ fontSize: 12, letterSpacing: '0.24em', textTransform: 'uppercase', color: '#64748b' }}>
304
+ Browser template
305
+ </span>
306
+ </div>
307
+ <h1
308
+ style={{
309
+ margin: 0,
310
+ color: '#020617',
311
+ fontSize: portrait ? Math.round(runtimeHeight * 0.042) : Math.round(runtimeHeight * 0.05),
312
+ lineHeight: 0.96,
313
+ letterSpacing: '-0.06em',
314
+ }}
315
+ >
316
+ {title}
317
+ </h1>
318
+ {subtitle ? (
319
+ <p style={{ margin: 0, color: '#334155', fontSize: portrait ? 18 : 20, lineHeight: 1.5 }}>{subtitle}</p>
320
+ ) : null}
321
+ </div>
322
+ <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', marginTop: 18 }}>
323
+ <button
324
+ style={{
325
+ padding: '10px 14px',
326
+ border: '1px solid rgba(2,6,23,0.12)',
327
+ borderRadius: 0,
328
+ background: accent,
329
+ color: '#f8fafc',
330
+ fontSize: 13,
331
+ fontWeight: 700,
332
+ letterSpacing: '0.04em',
333
+ }}
334
+ >
335
+ Open canvas
336
+ </button>
337
+ <button
338
+ style={{
339
+ padding: '10px 14px',
340
+ border: '1px solid rgba(2,6,23,0.12)',
341
+ borderRadius: 0,
342
+ background: 'rgba(15,23,42,0.04)',
343
+ color: '#0f172a',
344
+ fontSize: 13,
345
+ fontWeight: 700,
346
+ letterSpacing: '0.04em',
347
+ }}
348
+ >
349
+ View source
350
+ </button>
351
+ </div>
352
+ </div>
353
+
354
+ <div
355
+ style={{
356
+ display: 'grid',
357
+ gridTemplateColumns: portrait ? '1fr' : 'repeat(3, minmax(0, 1fr))',
358
+ gap: 12,
359
+ }}
360
+ >
361
+ {[
362
+ { label: 'Canvas height', value: '100%' },
363
+ { label: 'Layering', value: 'HTML → canvas' },
364
+ { label: 'Fallback', value: 'DOM preview' },
365
+ ].map((item, index) => (
366
+ <div
367
+ key={item.label}
368
+ style={{
369
+ padding: 14,
370
+ border: '1px solid rgba(15,23,42,0.12)',
371
+ background: index % 2 === 0 ? 'rgba(255,255,255,0.86)' : 'rgba(248,250,252,0.92)',
372
+ }}
373
+ >
374
+ <div style={{ fontSize: 11, letterSpacing: '0.22em', textTransform: 'uppercase', color: '#64748b' }}>{item.label}</div>
375
+ <div style={{ marginTop: 10, color: '#020617', fontSize: 18, fontWeight: 700 }}>{item.value}</div>
376
+ </div>
377
+ ))}
378
+ </div>
379
+ </div>
380
+
381
+ <div
382
+ style={{
383
+ position: 'relative',
384
+ minHeight: 0,
385
+ overflow: 'hidden',
386
+ border: '1px solid rgba(15,23,42,0.12)',
387
+ background:
388
+ 'linear-gradient(160deg, rgba(15,23,42,0.08) 0%, rgba(2,6,23,0.92) 64%, rgba(59,130,246,0.22) 100%)',
389
+ boxShadow: '0 26px 90px rgba(15,23,42,0.16)',
390
+ }}
391
+ >
392
+ <div
393
+ style={{
394
+ position: 'absolute',
395
+ inset: 0,
396
+ padding: 18,
397
+ display: 'grid',
398
+ gridTemplateRows: 'auto 1fr auto',
399
+ gap: 16,
400
+ }}
401
+ >
402
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12 }}>
403
+ <div>
404
+ <div style={{ fontSize: 11, letterSpacing: '0.28em', textTransform: 'uppercase', color: '#94a3b8' }}>Preview</div>
405
+ <div style={{ marginTop: 6, color: '#f8fafc', fontSize: 18, fontWeight: 700 }}>Rendered in canvas</div>
406
+ </div>
407
+ <div style={{ display: 'inline-flex', alignItems: 'center', gap: 8, color: '#cbd5e1', fontSize: 12 }}>
408
+ <span style={{ width: 8, height: 8, borderRadius: 9999, background: '#22c55e' }} />
409
+ Active
410
+ </div>
411
+ </div>
412
+
413
+ <div
414
+ style={{
415
+ display: 'grid',
416
+ gridTemplateColumns: portrait ? '1fr' : 'repeat(2, minmax(0, 1fr))',
417
+ gap: 12,
418
+ alignContent: 'start',
419
+ }}
420
+ >
421
+ {[
422
+ { title: 'Canvas fidelity', text: 'Use the browser layout and draw it directly to the output canvas.' },
423
+ { title: 'Live controls', text: 'Keep the HTML structure visible in Storybook when the flag is off.' },
424
+ { title: 'Composition-safe', text: 'Works with scene width, height, and frame data.' },
425
+ { title: 'Pixel density', text: 'Tune the canvas sharpness for high-DPI renders.' },
426
+ ].map((item) => (
427
+ <div
428
+ key={item.title}
429
+ style={{
430
+ padding: 14,
431
+ border: '1px solid rgba(255,255,255,0.12)',
432
+ background: 'rgba(2,6,23,0.56)',
433
+ }}
434
+ >
435
+ <div style={{ color: '#f8fafc', fontSize: 15, fontWeight: 700 }}>{item.title}</div>
436
+ <div style={{ marginTop: 8, color: '#cbd5e1', fontSize: 13, lineHeight: 1.55 }}>{item.text}</div>
437
+ </div>
438
+ ))}
439
+ </div>
440
+
441
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12 }}>
442
+ <div style={{ color: '#94a3b8', fontSize: 11, letterSpacing: '0.22em', textTransform: 'uppercase' }}>HTML in Canvas</div>
443
+ <div style={{ color: '#e2e8f0', fontSize: 12 }}>{secondaryAccent}</div>
444
+ </div>
445
+ </div>
446
+ </div>
447
+ </div>
448
+ </div>
449
+ )
450
+ }
451
+
452
+ function DashboardTemplate({
453
+ title,
454
+ subtitle,
455
+ badge,
456
+ accent = '#8b5cf6',
457
+ secondaryAccent = '#0f172a',
458
+ runtimeWidth,
459
+ runtimeHeight,
460
+ progress,
461
+ sceneType,
462
+ }: {
463
+ title: string
464
+ subtitle?: string
465
+ badge: string
466
+ accent?: string
467
+ secondaryAccent?: string
468
+ runtimeWidth: number
469
+ runtimeHeight: number
470
+ progress: number
471
+ sceneType: 'static' | 'animation'
472
+ }) {
473
+ const portrait = runtimeHeight > runtimeWidth
474
+ const barProgress = sceneType === 'animation' ? progress : 1
475
+ const bars = [54, 68, 42, 88, 62, 74, 36, 92, 58, 66]
476
+
477
+ return (
478
+ <div
479
+ style={{
480
+ width: '100%',
481
+ height: '100%',
482
+ display: 'grid',
483
+ gridTemplateRows: 'auto 1fr',
484
+ color: '#e2e8f0',
485
+ background:
486
+ 'radial-gradient(circle at 16% 12%, rgba(139,92,246,0.18) 0%, rgba(2,6,23,0.08) 36%, rgba(2,6,23,0.92) 100%), linear-gradient(180deg, #020617 0%, #0f172a 100%)',
487
+ }}
488
+ >
489
+ <div
490
+ style={{
491
+ display: 'flex',
492
+ alignItems: 'center',
493
+ justifyContent: 'space-between',
494
+ gap: 12,
495
+ padding: portrait ? '14px 16px' : '18px 22px',
496
+ borderBottom: '1px solid rgba(255,255,255,0.08)',
497
+ background: 'rgba(2,6,23,0.78)',
498
+ }}
499
+ >
500
+ <div style={{ display: 'grid', gap: 4 }}>
501
+ <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
502
+ <TemplateBadge label={badge} accent={accent} />
503
+ <span style={{ fontSize: 11, letterSpacing: '0.22em', textTransform: 'uppercase', color: '#94a3b8' }}>
504
+ Dashboard template
505
+ </span>
506
+ </div>
507
+ <h1 style={{ margin: 0, fontSize: portrait ? 20 : 24, letterSpacing: '-0.04em', color: '#f8fafc' }}>{title}</h1>
508
+ </div>
509
+ <div
510
+ style={{
511
+ display: 'inline-flex',
512
+ alignItems: 'center',
513
+ gap: 8,
514
+ padding: '10px 14px',
515
+ border: '1px solid rgba(255,255,255,0.14)',
516
+ background: 'rgba(15,23,42,0.72)',
517
+ color: '#cbd5e1',
518
+ fontSize: 12,
519
+ letterSpacing: '0.12em',
520
+ textTransform: 'uppercase',
521
+ }}
522
+ >
523
+ Live metrics
524
+ </div>
525
+ </div>
526
+
527
+ <div
528
+ style={{
529
+ padding: portrait ? 16 : 22,
530
+ display: 'grid',
531
+ gridTemplateColumns: portrait ? '1fr' : '1.3fr 0.7fr',
532
+ gap: portrait ? 16 : 20,
533
+ minWidth: 0,
534
+ minHeight: 0,
535
+ }}
536
+ >
537
+ <div
538
+ style={{
539
+ display: 'grid',
540
+ gap: 16,
541
+ minWidth: 0,
542
+ }}
543
+ >
544
+ <div
545
+ style={{
546
+ display: 'grid',
547
+ gridTemplateColumns: portrait ? '1fr 1fr' : 'repeat(4, minmax(0, 1fr))',
548
+ gap: 12,
549
+ }}
550
+ >
551
+ {[
552
+ { label: 'Sessions', value: '1.28M', delta: '+12.4%' },
553
+ { label: 'Conversion', value: '8.7%', delta: '+1.1%' },
554
+ { label: 'Latency', value: '124 ms', delta: '-9 ms' },
555
+ { label: 'Uptime', value: '99.98%', delta: '+0.02%' },
556
+ ].map((item, index) => (
557
+ <div
558
+ key={item.label}
559
+ style={{
560
+ padding: 14,
561
+ border: '1px solid rgba(255,255,255,0.08)',
562
+ background: index % 2 === 0 ? 'rgba(15,23,42,0.72)' : 'rgba(2,6,23,0.72)',
563
+ }}
564
+ >
565
+ <div style={{ color: '#94a3b8', fontSize: 11, letterSpacing: '0.24em', textTransform: 'uppercase' }}>
566
+ {item.label}
567
+ </div>
568
+ <div style={{ marginTop: 12, fontSize: 28, fontWeight: 800, letterSpacing: '-0.05em', color: '#f8fafc' }}>{item.value}</div>
569
+ <div style={{ marginTop: 8, color: accent, fontSize: 12, fontWeight: 700 }}>{item.delta}</div>
570
+ </div>
571
+ ))}
572
+ </div>
573
+
574
+ <div
575
+ style={{
576
+ padding: 16,
577
+ border: '1px solid rgba(255,255,255,0.08)',
578
+ background: 'rgba(2,6,23,0.72)',
579
+ }}
580
+ >
581
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12 }}>
582
+ <div>
583
+ <div style={{ color: '#94a3b8', fontSize: 11, letterSpacing: '0.24em', textTransform: 'uppercase' }}>Overview</div>
584
+ <div style={{ marginTop: 6, color: '#f8fafc', fontSize: 18, fontWeight: 700 }}>{subtitle ?? 'HTML rendered directly inside canvas'}</div>
585
+ </div>
586
+ <div style={{ color: '#cbd5e1', fontSize: 12, letterSpacing: '0.2em', textTransform: 'uppercase' }}>
587
+ {Math.round(barProgress * 100)}% ready
588
+ </div>
589
+ </div>
590
+
591
+ <div
592
+ style={{
593
+ marginTop: 18,
594
+ height: portrait ? 240 : 300,
595
+ display: 'grid',
596
+ gridTemplateColumns: `repeat(${bars.length}, minmax(0, 1fr))`,
597
+ alignItems: 'end',
598
+ gap: 10,
599
+ }}
600
+ >
601
+ {bars.map((value, index) => {
602
+ const animatedHeight = Math.max(16, Math.round(value * (0.8 + barProgress * 0.2)))
603
+ return (
604
+ <div
605
+ key={`${index}-${value}`}
606
+ style={{
607
+ height: '100%',
608
+ display: 'flex',
609
+ alignItems: 'end',
610
+ justifyContent: 'center',
611
+ }}
612
+ >
613
+ <div
614
+ style={{
615
+ width: '100%',
616
+ height: `${animatedHeight}%`,
617
+ minHeight: 12,
618
+ background: `linear-gradient(180deg, ${accent} 0%, ${secondaryAccent} 100%)`,
619
+ border: '1px solid rgba(255,255,255,0.08)',
620
+ boxShadow: '0 12px 30px rgba(15,23,42,0.24)',
621
+ }}
622
+ />
623
+ </div>
624
+ )
625
+ })}
626
+ </div>
627
+ </div>
628
+ </div>
629
+
630
+ <div
631
+ style={{
632
+ display: 'grid',
633
+ gap: 12,
634
+ alignContent: 'start',
635
+ minWidth: 0,
636
+ }}
637
+ >
638
+ <div
639
+ style={{
640
+ padding: 16,
641
+ border: '1px solid rgba(255,255,255,0.08)',
642
+ background: 'rgba(15,23,42,0.72)',
643
+ }}
644
+ >
645
+ <div style={{ color: '#94a3b8', fontSize: 11, letterSpacing: '0.24em', textTransform: 'uppercase' }}>Activity</div>
646
+ <div style={{ display: 'grid', gap: 12, marginTop: 14 }}>
647
+ {[
648
+ 'New deployment completed',
649
+ 'Peak traffic stabilized',
650
+ 'Background jobs cleared',
651
+ 'Preview canvas rendered',
652
+ ].map((item, index) => (
653
+ <div
654
+ key={item}
655
+ style={{
656
+ display: 'flex',
657
+ alignItems: 'center',
658
+ gap: 10,
659
+ paddingBottom: 12,
660
+ borderBottom: index === 3 ? 'none' : '1px solid rgba(255,255,255,0.08)',
661
+ }}
662
+ >
663
+ <span style={{ width: 8, height: 8, borderRadius: 9999, background: index % 2 === 0 ? accent : '#22c55e' }} />
664
+ <span style={{ color: '#e2e8f0', fontSize: 13, lineHeight: 1.5 }}>{item}</span>
665
+ </div>
666
+ ))}
667
+ </div>
668
+ </div>
669
+
670
+ <div
671
+ style={{
672
+ padding: 16,
673
+ border: '1px solid rgba(255,255,255,0.08)',
674
+ background: 'rgba(2,6,23,0.72)',
675
+ }}
676
+ >
677
+ <div style={{ color: '#94a3b8', fontSize: 11, letterSpacing: '0.24em', textTransform: 'uppercase' }}>Canvas notes</div>
678
+ <p style={{ margin: '12px 0 0', color: '#cbd5e1', fontSize: 13, lineHeight: 1.6 }}>
679
+ Use HtmlInCanvas for crisp DOM-to-canvas rendering, while keeping a fallback HTML preview when the browser flag is unavailable.
680
+ </p>
681
+ </div>
682
+ </div>
683
+ </div>
684
+ </div>
685
+ )
686
+ }
687
+
688
+ function EditorTemplate({
689
+ title,
690
+ subtitle,
691
+ badge,
692
+ accent = '#22c55e',
693
+ secondaryAccent = '#0f172a',
694
+ runtimeWidth,
695
+ runtimeHeight,
696
+ progress,
697
+ sceneType,
698
+ }: {
699
+ title: string
700
+ subtitle?: string
701
+ badge: string
702
+ accent?: string
703
+ secondaryAccent?: string
704
+ runtimeWidth: number
705
+ runtimeHeight: number
706
+ progress: number
707
+ sceneType: 'static' | 'animation'
708
+ }) {
709
+ const portrait = runtimeHeight > runtimeWidth
710
+ const reveal = sceneType === 'animation' ? progress : 1
711
+
712
+ return (
713
+ <div
714
+ style={{
715
+ width: '100%',
716
+ height: '100%',
717
+ display: 'grid',
718
+ gridTemplateRows: 'auto 1fr',
719
+ color: '#e2e8f0',
720
+ background:
721
+ 'radial-gradient(circle at 12% 12%, rgba(34,197,94,0.16) 0%, rgba(2,6,23,0.04) 38%, rgba(2,6,23,0.94) 100%), linear-gradient(180deg, #020617 0%, #0f172a 100%)',
722
+ }}
723
+ >
724
+ <div
725
+ style={{
726
+ display: 'flex',
727
+ alignItems: 'center',
728
+ justifyContent: 'space-between',
729
+ gap: 12,
730
+ padding: portrait ? '12px 14px' : '16px 20px',
731
+ borderBottom: '1px solid rgba(255,255,255,0.08)',
732
+ background: 'rgba(2,6,23,0.86)',
733
+ }}
734
+ >
735
+ <div style={{ display: 'grid', gap: 4 }}>
736
+ <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
737
+ <TemplateBadge label={badge} accent={accent} />
738
+ <span style={{ fontSize: 11, letterSpacing: '0.24em', textTransform: 'uppercase', color: '#94a3b8' }}>
739
+ Editor template
740
+ </span>
741
+ </div>
742
+ <h1 style={{ margin: 0, fontSize: portrait ? 20 : 24, letterSpacing: '-0.04em', color: '#f8fafc' }}>{title}</h1>
743
+ </div>
744
+ <div
745
+ style={{
746
+ display: 'inline-flex',
747
+ alignItems: 'center',
748
+ gap: 8,
749
+ padding: '10px 14px',
750
+ border: '1px solid rgba(255,255,255,0.14)',
751
+ background: 'rgba(15,23,42,0.72)',
752
+ color: '#cbd5e1',
753
+ fontSize: 12,
754
+ letterSpacing: '0.12em',
755
+ textTransform: 'uppercase',
756
+ }}
757
+ >
758
+ Live coding
759
+ </div>
760
+ </div>
761
+
762
+ <div
763
+ style={{
764
+ padding: portrait ? 16 : 20,
765
+ display: 'grid',
766
+ gridTemplateColumns: portrait ? '1fr' : '220px 1fr',
767
+ gap: portrait ? 14 : 18,
768
+ minWidth: 0,
769
+ minHeight: 0,
770
+ }}
771
+ >
772
+ <div
773
+ style={{
774
+ display: 'grid',
775
+ gap: 12,
776
+ alignContent: 'start',
777
+ padding: 14,
778
+ border: '1px solid rgba(255,255,255,0.08)',
779
+ background: 'rgba(15,23,42,0.74)',
780
+ }}
781
+ >
782
+ {['App.tsx', 'layout.tsx', 'theme.ts', 'preview.tsx', 'types.ts'].map((item, index) => (
783
+ <div
784
+ key={item}
785
+ style={{
786
+ padding: '10px 12px',
787
+ border: '1px solid rgba(255,255,255,0.08)',
788
+ background: index === 1 ? 'rgba(34,197,94,0.18)' : 'rgba(2,6,23,0.52)',
789
+ color: '#e2e8f0',
790
+ fontSize: 13,
791
+ display: 'flex',
792
+ alignItems: 'center',
793
+ justifyContent: 'space-between',
794
+ gap: 10,
795
+ }}
796
+ >
797
+ <span>{item}</span>
798
+ <span style={{ color: '#94a3b8', fontSize: 11 }}>{index + 1}</span>
799
+ </div>
800
+ ))}
801
+ </div>
802
+
803
+ <div
804
+ style={{
805
+ display: 'grid',
806
+ gridTemplateRows: 'auto 1fr auto',
807
+ gap: 12,
808
+ minWidth: 0,
809
+ minHeight: 0,
810
+ }}
811
+ >
812
+ <div
813
+ style={{
814
+ padding: 14,
815
+ border: '1px solid rgba(255,255,255,0.08)',
816
+ background: 'rgba(2,6,23,0.76)',
817
+ display: 'flex',
818
+ alignItems: 'center',
819
+ justifyContent: 'space-between',
820
+ gap: 12,
821
+ }}
822
+ >
823
+ <div style={{ display: 'flex', alignItems: 'center', gap: 8, color: '#cbd5e1', fontSize: 12 }}>
824
+ <span style={{ width: 8, height: 8, borderRadius: 9999, background: '#22c55e' }} />
825
+ Editor ready
826
+ </div>
827
+ <div style={{ color: '#94a3b8', fontSize: 11, letterSpacing: '0.22em', textTransform: 'uppercase' }}>
828
+ {Math.round(reveal * 100)}% synced
829
+ </div>
830
+ </div>
831
+
832
+ <div
833
+ style={{
834
+ display: 'grid',
835
+ gridTemplateColumns: portrait ? '1fr' : '1.2fr 0.8fr',
836
+ gap: 12,
837
+ minWidth: 0,
838
+ minHeight: 0,
839
+ }}
840
+ >
841
+ <div
842
+ style={{
843
+ padding: 16,
844
+ border: '1px solid rgba(255,255,255,0.08)',
845
+ background: 'rgba(2,6,23,0.88)',
846
+ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',
847
+ fontSize: portrait ? 12 : 13,
848
+ lineHeight: 1.72,
849
+ color: '#cbd5e1',
850
+ overflow: 'hidden',
851
+ }}
852
+ >
853
+ <div style={{ color: '#94a3b8' }}>{'const scene = {'}</div>
854
+ <div style={{ marginLeft: 18 }}>{`title: "${title}",`}</div>
855
+ <div style={{ marginLeft: 18 }}>{`subtitle: "${subtitle ?? 'Design in canvas'}",`}</div>
856
+ <div style={{ marginLeft: 18 }}>{`mode: "${sceneType}",`}</div>
857
+ <div style={{ marginLeft: 18, color: accent }}>{`badge: "${badge}",`}</div>
858
+ <div style={{ color: '#94a3b8' }}>{'}'}</div>
859
+ <div style={{ marginTop: 14, color: '#f8fafc' }}>{'return <HtmlInCanvas />'}</div>
860
+ </div>
861
+
862
+ <div
863
+ style={{
864
+ display: 'grid',
865
+ gap: 12,
866
+ alignContent: 'start',
867
+ }}
868
+ >
869
+ {[
870
+ { label: 'Compilation', value: 'fast refresh' },
871
+ { label: 'Preview', value: 'inline canvas' },
872
+ { label: 'Theme', value: secondaryAccent },
873
+ ].map((item) => (
874
+ <div
875
+ key={item.label}
876
+ style={{
877
+ padding: 14,
878
+ border: '1px solid rgba(255,255,255,0.08)',
879
+ background: 'rgba(15,23,42,0.72)',
880
+ }}
881
+ >
882
+ <div style={{ color: '#94a3b8', fontSize: 11, letterSpacing: '0.22em', textTransform: 'uppercase' }}>{item.label}</div>
883
+ <div style={{ marginTop: 10, color: '#f8fafc', fontSize: 16, fontWeight: 700 }}>{item.value}</div>
884
+ </div>
885
+ ))}
886
+ </div>
887
+ </div>
888
+
889
+ <div
890
+ style={{
891
+ padding: 14,
892
+ border: '1px solid rgba(255,255,255,0.08)',
893
+ background: `linear-gradient(90deg, ${accent} 0%, rgba(15,23,42,0.72) 100%)`,
894
+ color: '#f8fafc',
895
+ display: 'flex',
896
+ justifyContent: 'space-between',
897
+ gap: 12,
898
+ alignItems: 'center',
899
+ }}
900
+ >
901
+ <span style={{ fontSize: 12, letterSpacing: '0.18em', textTransform: 'uppercase' }}>Inline preview</span>
902
+ <span style={{ fontSize: 12 }}>{sceneType === 'animation' ? 'animated' : 'static'}</span>
903
+ </div>
904
+ </div>
905
+ </div>
906
+ </div>
907
+ )
908
+ }
909
+
910
+ function DocsTemplate({
911
+ title,
912
+ subtitle,
913
+ badge,
914
+ accent = '#38bdf8',
915
+ secondaryAccent = '#0f172a',
916
+ runtimeWidth,
917
+ runtimeHeight,
918
+ progress,
919
+ sceneType,
920
+ }: {
921
+ title: string
922
+ subtitle?: string
923
+ badge: string
924
+ accent?: string
925
+ secondaryAccent?: string
926
+ runtimeWidth: number
927
+ runtimeHeight: number
928
+ progress: number
929
+ sceneType: 'static' | 'animation'
930
+ }) {
931
+ const portrait = runtimeHeight > runtimeWidth
932
+ const reveal = sceneType === 'animation' ? progress : 1
933
+
934
+ return (
935
+ <div
936
+ style={{
937
+ width: '100%',
938
+ height: '100%',
939
+ display: 'grid',
940
+ gridTemplateRows: 'auto 1fr',
941
+ color: '#e2e8f0',
942
+ background:
943
+ 'radial-gradient(circle at 20% 10%, rgba(56,189,248,0.18) 0%, rgba(2,6,23,0.04) 40%, rgba(2,6,23,0.96) 100%), linear-gradient(180deg, #020617 0%, #0f172a 100%)',
944
+ }}
945
+ >
946
+ <div
947
+ style={{
948
+ display: 'flex',
949
+ alignItems: 'center',
950
+ justifyContent: 'space-between',
951
+ gap: 12,
952
+ padding: portrait ? '12px 14px' : '16px 20px',
953
+ borderBottom: '1px solid rgba(255,255,255,0.08)',
954
+ background: 'rgba(2,6,23,0.84)',
955
+ }}
956
+ >
957
+ <div style={{ display: 'grid', gap: 4 }}>
958
+ <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
959
+ <TemplateBadge label={badge} accent={accent} />
960
+ <span style={{ fontSize: 11, letterSpacing: '0.24em', textTransform: 'uppercase', color: '#94a3b8' }}>
961
+ Docs template
962
+ </span>
963
+ </div>
964
+ <h1 style={{ margin: 0, fontSize: portrait ? 20 : 24, letterSpacing: '-0.04em', color: '#f8fafc' }}>{title}</h1>
965
+ </div>
966
+ <div
967
+ style={{
968
+ display: 'inline-flex',
969
+ alignItems: 'center',
970
+ gap: 8,
971
+ padding: '10px 14px',
972
+ border: '1px solid rgba(255,255,255,0.14)',
973
+ background: 'rgba(15,23,42,0.72)',
974
+ color: '#cbd5e1',
975
+ fontSize: 12,
976
+ letterSpacing: '0.12em',
977
+ textTransform: 'uppercase',
978
+ }}
979
+ >
980
+ Readme preview
981
+ </div>
982
+ </div>
983
+
984
+ <div
985
+ style={{
986
+ padding: portrait ? 16 : 22,
987
+ display: 'grid',
988
+ gridTemplateColumns: portrait ? '1fr' : '1fr 260px',
989
+ gap: portrait ? 16 : 20,
990
+ minWidth: 0,
991
+ minHeight: 0,
992
+ }}
993
+ >
994
+ <article
995
+ style={{
996
+ padding: portrait ? 18 : 22,
997
+ border: '1px solid rgba(255,255,255,0.08)',
998
+ background: 'rgba(2,6,23,0.82)',
999
+ boxShadow: '0 22px 80px rgba(15,23,42,0.18)',
1000
+ minWidth: 0,
1001
+ }}
1002
+ >
1003
+ <div style={{ display: 'grid', gap: 12, maxWidth: portrait ? '100%' : '92%' }}>
1004
+ <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
1005
+ <TemplateBadge label="Html in Canvas" accent={accent} />
1006
+ <span style={{ fontSize: 12, letterSpacing: '0.24em', textTransform: 'uppercase', color: '#64748b' }}>
1007
+ Documentation template
1008
+ </span>
1009
+ </div>
1010
+ <h2 style={{ margin: 0, color: '#f8fafc', fontSize: portrait ? 28 : 34, lineHeight: 1.04, letterSpacing: '-0.05em' }}>
1011
+ {subtitle ?? 'Compose structured documentation directly inside a Remotion frame.'}
1012
+ </h2>
1013
+ <p style={{ margin: 0, color: '#cbd5e1', fontSize: portrait ? 16 : 18, lineHeight: 1.7 }}>
1014
+ HtmlInCanvas is useful for docs-heavy scenes where headings, callouts, and references should remain crisp inside the output video.
1015
+ </p>
1016
+ </div>
1017
+
1018
+ <div
1019
+ style={{
1020
+ marginTop: 18,
1021
+ display: 'grid',
1022
+ gridTemplateColumns: portrait ? '1fr' : 'repeat(2, minmax(0, 1fr))',
1023
+ gap: 12,
1024
+ }}
1025
+ >
1026
+ {[
1027
+ 'Concept overview',
1028
+ 'Implementation notes',
1029
+ 'Checklists and callouts',
1030
+ 'Embedded references',
1031
+ ].map((item, index) => (
1032
+ <div
1033
+ key={item}
1034
+ style={{
1035
+ padding: 14,
1036
+ border: '1px solid rgba(255,255,255,0.08)',
1037
+ background: index % 2 === 0 ? 'rgba(15,23,42,0.72)' : 'rgba(2,6,23,0.72)',
1038
+ }}
1039
+ >
1040
+ <div style={{ color: '#94a3b8', fontSize: 11, letterSpacing: '0.22em', textTransform: 'uppercase' }}>
1041
+ Section {index + 1}
1042
+ </div>
1043
+ <div style={{ marginTop: 10, color: '#f8fafc', fontSize: 16, fontWeight: 700 }}>{item}</div>
1044
+ </div>
1045
+ ))}
1046
+ </div>
1047
+ </article>
1048
+
1049
+ <aside
1050
+ style={{
1051
+ display: 'grid',
1052
+ gap: 12,
1053
+ alignContent: 'start',
1054
+ minWidth: 0,
1055
+ }}
1056
+ >
1057
+ <div
1058
+ style={{
1059
+ padding: 16,
1060
+ border: '1px solid rgba(255,255,255,0.08)',
1061
+ background: 'rgba(15,23,42,0.72)',
1062
+ }}
1063
+ >
1064
+ <div style={{ color: '#94a3b8', fontSize: 11, letterSpacing: '0.24em', textTransform: 'uppercase' }}>Outline</div>
1065
+ <div style={{ display: 'grid', gap: 10, marginTop: 14 }}>
1066
+ {['Intro', 'Goals', 'Examples', 'API', 'Summary'].map((item, index) => (
1067
+ <div key={item} style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
1068
+ <span style={{ width: 8, height: 8, borderRadius: 9999, background: index === 0 ? accent : '#38bdf8' }} />
1069
+ <span style={{ color: '#e2e8f0', fontSize: 13 }}>{item}</span>
1070
+ </div>
1071
+ ))}
1072
+ </div>
1073
+ </div>
1074
+
1075
+ <div
1076
+ style={{
1077
+ padding: 16,
1078
+ border: '1px solid rgba(255,255,255,0.08)',
1079
+ background: 'rgba(2,6,23,0.72)',
1080
+ }}
1081
+ >
1082
+ <div style={{ color: '#94a3b8', fontSize: 11, letterSpacing: '0.24em', textTransform: 'uppercase' }}>Progress</div>
1083
+ <div
1084
+ style={{
1085
+ marginTop: 14,
1086
+ height: 12,
1087
+ border: '1px solid rgba(255,255,255,0.08)',
1088
+ background: 'rgba(255,255,255,0.06)',
1089
+ overflow: 'hidden',
1090
+ }}
1091
+ >
1092
+ <div
1093
+ style={{
1094
+ width: `${Math.round(reveal * 100)}%`,
1095
+ height: '100%',
1096
+ background: `linear-gradient(90deg, ${accent} 0%, ${secondaryAccent} 100%)`,
1097
+ }}
1098
+ />
1099
+ </div>
1100
+ <p style={{ margin: '12px 0 0', color: '#cbd5e1', fontSize: 13, lineHeight: 1.6 }}>
1101
+ A documentation layout can keep structure, references, and notes aligned while still rendering cleanly in canvas.
1102
+ </p>
1103
+ </div>
1104
+ </aside>
1105
+ </div>
1106
+ </div>
1107
+ )
1108
+ }
1109
+
1110
+ export function createHtmlInCanvasScene(config: HtmlCanvasSceneConfig) {
1111
+ const componentMetadata = defineScenePluginMetadata({
1112
+ resourceKind: 'scene',
1113
+ name: config.name,
1114
+ description: `${config.description} Supports a full-bleed html fragment input.`,
1115
+ sourceFile: config.sourceFile,
1116
+ pluginKey: config.pluginKey,
1117
+ tags: ['scene', 'html-in-canvas', config.template, config.aspectRatio === '16:9' ? 'landscape' : 'horizontal'],
1118
+ aspectRatio: config.aspectRatio,
1119
+ sceneType: 'scene',
1120
+ sceneFamily: 'custom',
1121
+ rootLayout: 'absolute-fill',
1122
+ propsTypeName: 'DefaultHtmlInCanvasSceneProps',
1123
+ })
1124
+
1125
+ const Scene = VideoComponent(componentMetadata)(
1126
+ defineSceneComponent({
1127
+ family: 'custom',
1128
+ propsSchema: z.object({
1129
+ sceneId: z.string().optional(),
1130
+ sceneName: z.string().optional(),
1131
+ title: z.string().optional(),
1132
+ subtitle: z.string().optional(),
1133
+ badge: z.string().optional(),
1134
+ accent: z.string().optional(),
1135
+ secondaryAccent: z.string().optional(),
1136
+ textColor: z.string().optional(),
1137
+ html: z.string().optional(),
1138
+ }),
1139
+ component: function HtmlInCanvasScene({
1140
+ id,
1141
+ name,
1142
+ sceneId,
1143
+ sceneName,
1144
+ title,
1145
+ subtitle,
1146
+ badge,
1147
+ accent,
1148
+ secondaryAccent,
1149
+ textColor,
1150
+ html,
1151
+ }: DefaultHtmlInCanvasSceneProps) {
1152
+ const runtime = useRemotionSceneRuntime()
1153
+ const sceneConfig = useSceneConfig()
1154
+ const frame = useCurrentFrame()
1155
+ const { fps } = useVideoConfig()
1156
+ const progress =
1157
+ sceneConfig.sceneType === 'animation'
1158
+ ? spring({
1159
+ frame,
1160
+ fps,
1161
+ config: { damping: 18, mass: 0.8, stiffness: 120 },
1162
+ })
1163
+ : 1
1164
+ const contentTitle = title ?? (config.template === 'browser' ? 'Browser in Canvas' : 'Dashboard in Canvas')
1165
+ const contentSubtitle =
1166
+ subtitle ??
1167
+ (config.template === 'browser'
1168
+ ? 'Render a browser-style DOM tree directly into a Remotion canvas.'
1169
+ : 'Compose dashboard UI in DOM and capture it as a canvas frame.')
1170
+ const contentBadge = badge ?? (config.template === 'browser' ? 'Browser Canvas' : 'Dashboard Canvas')
1171
+ const baseTheme = config.template === 'browser' ? 'rgba(248,250,252,1)' : 'rgba(2,6,23,1)'
1172
+ const htmlMode = typeof html === 'string' && html.trim().length > 0
1173
+
1174
+ return (
1175
+ <BaseRemotionScene
1176
+ id={id ?? sceneId}
1177
+ name={name ?? sceneName ?? contentTitle}
1178
+ style={{
1179
+ background:
1180
+ config.template === 'browser'
1181
+ ? `linear-gradient(180deg, ${secondaryAccent ?? '#020617'} 0%, #0f172a 100%)`
1182
+ : `radial-gradient(circle at 50% 12%, ${accent ?? 'rgba(139,92,246,0.24)'} 0%, #020617 52%, #000000 100%)`,
1183
+ color: textColor ?? '#f8fafc',
1184
+ padding: htmlMode ? 0 : Math.round(runtime.height * 0.02),
1185
+ }}
1186
+ >
1187
+ {htmlMode ? (
1188
+ <HtmlMarkupSurface width={runtime.width} height={runtime.height} html={html} theme={baseTheme} />
1189
+ ) : (
1190
+ <HtmlCanvasSurface width={runtime.width} height={runtime.height} theme={baseTheme}>
1191
+ {config.template === 'browser' ? (
1192
+ <BrowserTemplate
1193
+ title={contentTitle}
1194
+ subtitle={contentSubtitle}
1195
+ badge={contentBadge}
1196
+ accent={accent}
1197
+ secondaryAccent={secondaryAccent}
1198
+ runtimeWidth={runtime.width}
1199
+ runtimeHeight={runtime.height}
1200
+ progress={progress}
1201
+ sceneType={sceneConfig.sceneType}
1202
+ />
1203
+ ) : (
1204
+ <DashboardTemplate
1205
+ title={contentTitle}
1206
+ subtitle={contentSubtitle}
1207
+ badge={contentBadge}
1208
+ accent={accent}
1209
+ secondaryAccent={secondaryAccent}
1210
+ runtimeWidth={runtime.width}
1211
+ runtimeHeight={runtime.height}
1212
+ progress={progress}
1213
+ sceneType={sceneConfig.sceneType}
1214
+ />
1215
+ )}
1216
+ </HtmlCanvasSurface>
1217
+ )}
1218
+ </BaseRemotionScene>
1219
+ )
1220
+ },
1221
+ }),
1222
+ )
1223
+
1224
+ return { componentMetadata, Scene }
1225
+ }
1226
+
1227
+ const browserLandscape = createHtmlInCanvasScene({
1228
+ name: 'DefaultHtmlInCanvasBrowserSceneLandscape',
1229
+ description: 'Browser-style HtmlInCanvas scene for 16:9 landscape previews',
1230
+ sourceFile: 'src/core/scene/html-in-canvas/shared/default-html-in-canvas-scene.tsx',
1231
+ pluginKey: 'core.html-in-canvas.browser',
1232
+ aspectRatio: '16:9',
1233
+ template: 'browser',
1234
+ })
1235
+
1236
+ const browserHorizontal = createHtmlInCanvasScene({
1237
+ name: 'DefaultHtmlInCanvasBrowserSceneHorizontal',
1238
+ description: 'Browser-style HtmlInCanvas scene for 9:16 vertical previews',
1239
+ sourceFile: 'src/core/scene/html-in-canvas/shared/default-html-in-canvas-scene.tsx',
1240
+ pluginKey: 'core.html-in-canvas.browser',
1241
+ aspectRatio: '9:16',
1242
+ template: 'browser',
1243
+ })
1244
+
1245
+ const dashboardLandscape = createHtmlInCanvasScene({
1246
+ name: 'DefaultHtmlInCanvasDashboardSceneLandscape',
1247
+ description: 'Dashboard-style HtmlInCanvas scene for 16:9 landscape previews',
1248
+ sourceFile: 'src/core/scene/html-in-canvas/shared/default-html-in-canvas-scene.tsx',
1249
+ pluginKey: 'core.html-in-canvas.dashboard',
1250
+ aspectRatio: '16:9',
1251
+ template: 'dashboard',
1252
+ })
1253
+
1254
+ const dashboardHorizontal = createHtmlInCanvasScene({
1255
+ name: 'DefaultHtmlInCanvasDashboardSceneHorizontal',
1256
+ description: 'Dashboard-style HtmlInCanvas scene for 9:16 vertical previews',
1257
+ sourceFile: 'src/core/scene/html-in-canvas/shared/default-html-in-canvas-scene.tsx',
1258
+ pluginKey: 'core.html-in-canvas.dashboard',
1259
+ aspectRatio: '9:16',
1260
+ template: 'dashboard',
1261
+ })
1262
+
1263
+ const editorLandscape = createHtmlInCanvasScene({
1264
+ name: 'DefaultHtmlInCanvasEditorSceneLandscape',
1265
+ description: 'Editor-style HtmlInCanvas scene for 16:9 landscape previews',
1266
+ sourceFile: 'src/core/scene/html-in-canvas/shared/default-html-in-canvas-scene.tsx',
1267
+ pluginKey: 'core.html-in-canvas.editor',
1268
+ aspectRatio: '16:9',
1269
+ template: 'editor',
1270
+ })
1271
+
1272
+ const editorHorizontal = createHtmlInCanvasScene({
1273
+ name: 'DefaultHtmlInCanvasEditorSceneHorizontal',
1274
+ description: 'Editor-style HtmlInCanvas scene for 9:16 vertical previews',
1275
+ sourceFile: 'src/core/scene/html-in-canvas/shared/default-html-in-canvas-scene.tsx',
1276
+ pluginKey: 'core.html-in-canvas.editor',
1277
+ aspectRatio: '9:16',
1278
+ template: 'editor',
1279
+ })
1280
+
1281
+ const docsLandscape = createHtmlInCanvasScene({
1282
+ name: 'DefaultHtmlInCanvasDocsSceneLandscape',
1283
+ description: 'Docs-style HtmlInCanvas scene for 16:9 landscape previews',
1284
+ sourceFile: 'src/core/scene/html-in-canvas/shared/default-html-in-canvas-scene.tsx',
1285
+ pluginKey: 'core.html-in-canvas.docs',
1286
+ aspectRatio: '16:9',
1287
+ template: 'docs',
1288
+ })
1289
+
1290
+ const docsHorizontal = createHtmlInCanvasScene({
1291
+ name: 'DefaultHtmlInCanvasDocsSceneHorizontal',
1292
+ description: 'Docs-style HtmlInCanvas scene for 9:16 vertical previews',
1293
+ sourceFile: 'src/core/scene/html-in-canvas/shared/default-html-in-canvas-scene.tsx',
1294
+ pluginKey: 'core.html-in-canvas.docs',
1295
+ aspectRatio: '9:16',
1296
+ template: 'docs',
1297
+ })
1298
+
1299
+ export const DefaultHtmlInCanvasBrowserSceneLandscape = browserLandscape.Scene
1300
+ export const DefaultHtmlInCanvasBrowserSceneHorizontal = browserHorizontal.Scene
1301
+ export const DefaultHtmlInCanvasDashboardSceneLandscape = dashboardLandscape.Scene
1302
+ export const DefaultHtmlInCanvasDashboardSceneHorizontal = dashboardHorizontal.Scene
1303
+ export const DefaultHtmlInCanvasEditorSceneLandscape = editorLandscape.Scene
1304
+ export const DefaultHtmlInCanvasEditorSceneHorizontal = editorHorizontal.Scene
1305
+ export const DefaultHtmlInCanvasDocsSceneLandscape = docsLandscape.Scene
1306
+ export const DefaultHtmlInCanvasDocsSceneHorizontal = docsHorizontal.Scene
1307
+
1308
+ export const DefaultHtmlInCanvasBrowserSceneLandscapeMetadata = browserLandscape.componentMetadata
1309
+ export const DefaultHtmlInCanvasBrowserSceneHorizontalMetadata = browserHorizontal.componentMetadata
1310
+ export const DefaultHtmlInCanvasDashboardSceneLandscapeMetadata = dashboardLandscape.componentMetadata
1311
+ export const DefaultHtmlInCanvasDashboardSceneHorizontalMetadata = dashboardHorizontal.componentMetadata
1312
+ export const DefaultHtmlInCanvasEditorSceneLandscapeMetadata = editorLandscape.componentMetadata
1313
+ export const DefaultHtmlInCanvasEditorSceneHorizontalMetadata = editorHorizontal.componentMetadata
1314
+ export const DefaultHtmlInCanvasDocsSceneLandscapeMetadata = docsLandscape.componentMetadata
1315
+ export const DefaultHtmlInCanvasDocsSceneHorizontalMetadata = docsHorizontal.componentMetadata