@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,639 @@
1
+ import { useMemo } from 'react'
2
+
3
+ import { z } from 'zod'
4
+
5
+ import { VideoComponent, defineScenePluginMetadata } from '@vibecuting/component-project-helper'
6
+ import { Easing, Img, interpolate, spring, useCurrentFrame, useVideoConfig } from 'remotion'
7
+
8
+ import { BaseRemotionScene, type BaseRemotionSceneProps, useRemotionSceneRuntime, useSceneConfig } from '../../../../../base'
9
+ import { defineSceneComponent } from '../../../../../plugins/scene-component'
10
+
11
+ export type PhotoEffectType =
12
+ | 'vignette'
13
+ | 'grain'
14
+ | 'glow'
15
+ | 'warmth'
16
+ | 'soft-focus'
17
+ | 'mono'
18
+ | 'sepia'
19
+ | 'duotone'
20
+ | 'cool-tone'
21
+ | 'vibrant'
22
+ | 'dream'
23
+ | 'light-leak'
24
+ | 'chrome'
25
+ | 'noir'
26
+ | 'retro'
27
+ | 'infrared'
28
+ | 'pastel'
29
+ | 'halation'
30
+
31
+ export interface PhotoEffect {
32
+ type: PhotoEffectType
33
+ intensity?: number
34
+ hue?: string
35
+ secondaryHue?: string
36
+ }
37
+
38
+ export interface DefaultEffectsPhotoSceneProps extends BaseRemotionSceneProps {
39
+ sceneId?: string
40
+ sceneName?: string
41
+ title?: string
42
+ subtitle?: string
43
+ badge?: string
44
+ imageSrc: string
45
+ effects?: PhotoEffect[]
46
+ accent?: string
47
+ secondaryAccent?: string
48
+ textColor?: string
49
+ }
50
+
51
+ export const componentMetadata = defineScenePluginMetadata({
52
+ resourceKind: 'scene',
53
+ name: 'DefaultEffectsPhotoScene',
54
+ description: 'Photo scene with layered Remotion effects and cinematic grading',
55
+ sourceFile: 'src/core/scene/photo/effects-photo/default-effects-photo-scene/default-effects-photo-scene.tsx',
56
+ pluginKey: 'core.photo.effects-photo',
57
+ tags: ['scene', 'photo', 'effects', 'image', 'cinematic'],
58
+ aspectRatio: '16:9',
59
+ sceneType: 'scene',
60
+ sceneFamily: 'custom',
61
+ rootLayout: 'absolute-fill',
62
+ propsTypeName: 'DefaultEffectsPhotoSceneProps',
63
+ })
64
+
65
+ function matchesEffect(effects: PhotoEffect[] | undefined, type: PhotoEffectType) {
66
+ return effects?.some((effect) => effect.type === type) ?? false
67
+ }
68
+
69
+ function effectIntensity(effects: PhotoEffect[] | undefined, type: PhotoEffectType, fallback: number) {
70
+ return effects?.find((effect) => effect.type === type)?.intensity ?? fallback
71
+ }
72
+
73
+ function effectHue(effects: PhotoEffect[] | undefined, type: PhotoEffectType, fallback: string) {
74
+ return effects?.find((effect) => effect.type === type)?.hue ?? fallback
75
+ }
76
+
77
+ function effectSecondaryHue(effects: PhotoEffect[] | undefined, type: PhotoEffectType, fallback: string) {
78
+ return effects?.find((effect) => effect.type === type)?.secondaryHue ?? fallback
79
+ }
80
+
81
+ export const DefaultEffectsPhotoScene = VideoComponent(componentMetadata)(
82
+ defineSceneComponent({
83
+ family: 'custom',
84
+ propsSchema: z.object({
85
+ sceneId: z.string().optional(),
86
+ sceneName: z.string().optional(),
87
+ title: z.string().optional(),
88
+ subtitle: z.string().optional(),
89
+ badge: z.string().optional(),
90
+ imageSrc: z.string(),
91
+ effects: z
92
+ .array(
93
+ z.object({
94
+ type: z.enum([
95
+ 'vignette',
96
+ 'grain',
97
+ 'glow',
98
+ 'warmth',
99
+ 'soft-focus',
100
+ 'mono',
101
+ 'sepia',
102
+ 'duotone',
103
+ 'cool-tone',
104
+ 'vibrant',
105
+ 'dream',
106
+ 'light-leak',
107
+ 'chrome',
108
+ 'noir',
109
+ 'retro',
110
+ 'infrared',
111
+ 'pastel',
112
+ 'halation',
113
+ ]),
114
+ intensity: z.number().min(0).max(1).optional(),
115
+ hue: z.string().optional(),
116
+ secondaryHue: z.string().optional(),
117
+ }),
118
+ )
119
+ .optional(),
120
+ accent: z.string().optional(),
121
+ secondaryAccent: z.string().optional(),
122
+ textColor: z.string().optional(),
123
+ }),
124
+ component: function DefaultEffectsPhotoScene({
125
+ id,
126
+ name,
127
+ sceneId,
128
+ sceneName,
129
+ title,
130
+ subtitle,
131
+ badge,
132
+ imageSrc,
133
+ effects,
134
+ accent,
135
+ secondaryAccent,
136
+ textColor,
137
+ }: DefaultEffectsPhotoSceneProps) {
138
+ const runtime = useRemotionSceneRuntime()
139
+ const sceneConfig = useSceneConfig()
140
+ const frame = useCurrentFrame()
141
+ const { fps } = useVideoConfig()
142
+ const portrait = runtime.height > runtime.width
143
+ const animated = sceneConfig.sceneType === 'animation'
144
+ const animationProgress =
145
+ sceneConfig.sceneType === 'animation'
146
+ ? spring({
147
+ frame,
148
+ fps,
149
+ config: { damping: 22, mass: 0.8, stiffness: 130 },
150
+ })
151
+ : 1
152
+ const reveal = sceneConfig.sceneType === 'animation' ? spring({ frame: Math.max(0, frame - 6), fps, config: { damping: 20, mass: 0.7, stiffness: 150 } }) : 1
153
+ const focusDrift = sceneConfig.sceneType === 'animation' ? Math.sin((frame / fps) * Math.PI * 0.75) : 0
154
+ const scale = 1.01 + (1 - animationProgress) * 0.06 + focusDrift * 0.008
155
+ const translateX = (1 - animationProgress) * (portrait ? -8 : -12) + focusDrift * (portrait ? 8 : 12)
156
+ const translateY = (1 - animationProgress) * 10 + focusDrift * 16
157
+ const titleSize = Math.round(runtime.height * (portrait ? 0.034 : 0.04))
158
+ const subtitleSize = Math.round(runtime.height * 0.017)
159
+ const framePaddingX = Math.round(runtime.width * (portrait ? 0.015 : 0.014))
160
+ const framePaddingY = Math.round(runtime.height * (portrait ? 0.014 : 0.012))
161
+ const frameLeft = framePaddingX
162
+ const frameTop = framePaddingY
163
+ const frameWidth = Math.max(1, runtime.width - framePaddingX * 2)
164
+ const frameHeight = Math.max(1, runtime.height - framePaddingY * 2)
165
+ const hasMono = matchesEffect(effects, 'mono')
166
+ const hasSepia = matchesEffect(effects, 'sepia')
167
+ const hasDuotone = matchesEffect(effects, 'duotone')
168
+ const hasCoolTone = matchesEffect(effects, 'cool-tone')
169
+ const hasVibrant = matchesEffect(effects, 'vibrant')
170
+ const hasDream = matchesEffect(effects, 'dream')
171
+ const hasLightLeak = matchesEffect(effects, 'light-leak')
172
+ const hasChrome = matchesEffect(effects, 'chrome')
173
+ const hasNoir = matchesEffect(effects, 'noir')
174
+ const hasRetro = matchesEffect(effects, 'retro')
175
+ const hasInfrared = matchesEffect(effects, 'infrared')
176
+ const hasPastel = matchesEffect(effects, 'pastel')
177
+ const hasHalation = matchesEffect(effects, 'halation')
178
+ const monoIntensity = effectIntensity(effects, 'mono', 1)
179
+ const sepiaIntensity = effectIntensity(effects, 'sepia', 0.82)
180
+ const duotoneIntensity = effectIntensity(effects, 'duotone', 0.72)
181
+ const coolToneIntensity = effectIntensity(effects, 'cool-tone', 0.65)
182
+ const vibrantIntensity = effectIntensity(effects, 'vibrant', 0.68)
183
+ const dreamIntensity = effectIntensity(effects, 'dream', 0.45)
184
+ const lightLeakIntensity = effectIntensity(effects, 'light-leak', 0.58)
185
+ const chromeIntensity = effectIntensity(effects, 'chrome', 0.56)
186
+ const noirIntensity = effectIntensity(effects, 'noir', 0.88)
187
+ const retroIntensity = effectIntensity(effects, 'retro', 0.7)
188
+ const infraredIntensity = effectIntensity(effects, 'infrared', 0.62)
189
+ const pastelIntensity = effectIntensity(effects, 'pastel', 0.68)
190
+ const halationIntensity = effectIntensity(effects, 'halation', 0.58)
191
+ const duotonePrimary = effectHue(effects, 'duotone', accent ?? '#2563eb')
192
+ const duotoneSecondary = effectSecondaryHue(effects, 'duotone', secondaryAccent ?? '#f97316')
193
+ const coolToneHue = effectHue(effects, 'cool-tone', '#0f172a')
194
+ const lightLeakHue = effectHue(effects, 'light-leak', accent ?? '#fde68a')
195
+ const chromeHue = effectHue(effects, 'chrome', '#f8fafc')
196
+ const noirHue = effectHue(effects, 'noir', '#020617')
197
+ const retroHue = effectHue(effects, 'retro', '#f59e0b')
198
+ const infraredHue = effectHue(effects, 'infrared', '#ef4444')
199
+ const pastelHue = effectHue(effects, 'pastel', '#f9a8d4')
200
+ const halationHue = effectHue(effects, 'halation', '#fef3c7')
201
+ const imageFilter = [
202
+ animated ? 'brightness(1.08) contrast(1.04) saturate(1.08)' : 'brightness(1.88) contrast(1.16) saturate(1.2)',
203
+ hasMono ? `grayscale(${monoIntensity}) contrast(${1.04 + monoIntensity * 0.18})` : '',
204
+ hasSepia ? `sepia(${sepiaIntensity}) saturate(${1.05 + sepiaIntensity * 0.28})` : '',
205
+ hasDuotone ? `grayscale(1) contrast(${1.08 + duotoneIntensity * 0.12}) brightness(${0.98 + duotoneIntensity * 0.04})` : '',
206
+ hasCoolTone ? `hue-rotate(-24deg) saturate(${1.02 + coolToneIntensity * 0.14})` : '',
207
+ hasVibrant ? `saturate(${1.34 + vibrantIntensity * 0.28}) contrast(${1.06 + vibrantIntensity * 0.08})` : '',
208
+ hasDream ? `blur(${1 + dreamIntensity * 1.3}px) saturate(${1.06 + dreamIntensity * 0.1}) brightness(${1.04 + dreamIntensity * 0.05})` : '',
209
+ hasChrome ? `grayscale(0.12) contrast(${1.18 + chromeIntensity * 0.12}) saturate(${1.06 + chromeIntensity * 0.16}) brightness(${1.02 + chromeIntensity * 0.04})` : '',
210
+ hasNoir ? `grayscale(1) contrast(${1.3 + noirIntensity * 0.18}) brightness(${0.88 + noirIntensity * 0.05})` : '',
211
+ hasRetro ? `sepia(${0.55 + retroIntensity * 0.22}) saturate(${1.14 + retroIntensity * 0.22}) contrast(${1.08 + retroIntensity * 0.06})` : '',
212
+ hasInfrared ? `hue-rotate(168deg) saturate(${1.42 + infraredIntensity * 0.18}) contrast(${1.12 + infraredIntensity * 0.1})` : '',
213
+ hasPastel ? `saturate(${0.82 + pastelIntensity * 0.15}) brightness(${1.08 + pastelIntensity * 0.04}) contrast(${0.92 + pastelIntensity * 0.06})` : '',
214
+ hasHalation ? `brightness(${1.05 + halationIntensity * 0.04}) contrast(${1.12 + halationIntensity * 0.08}) saturate(${1.1 + halationIntensity * 0.12})` : '',
215
+ ]
216
+ .filter(Boolean)
217
+ .join(' ')
218
+ const vignette = matchesEffect(effects, 'vignette')
219
+ const grain = matchesEffect(effects, 'grain')
220
+ const glow = matchesEffect(effects, 'glow')
221
+ const warmth = matchesEffect(effects, 'warmth')
222
+ const softFocus = matchesEffect(effects, 'soft-focus')
223
+ const vignetteOpacity = effectIntensity(effects, 'vignette', 0.52) * (0.65 + reveal * 0.35)
224
+ const glowOpacity = effectIntensity(effects, 'glow', 0.45) * (0.7 + reveal * 0.3)
225
+ const grainOpacity = effectIntensity(effects, 'grain', 0.12)
226
+ const warmthHue = effects?.find((effect) => effect.type === 'warmth')?.hue ?? accent ?? '#f97316'
227
+ const dreamOpacity = dreamIntensity * (0.18 + reveal * 0.08)
228
+ const chromeOpacity = chromeIntensity * (0.08 + reveal * 0.12)
229
+ const lightLeakOpacity = lightLeakIntensity * (0.1 + reveal * 0.08)
230
+ const noirOpacity = noirIntensity * (0.16 + reveal * 0.1)
231
+ const retroOpacity = retroIntensity * (0.14 + reveal * 0.08)
232
+ const infraredOpacity = infraredIntensity * (0.18 + reveal * 0.06)
233
+ const pastelOpacity = pastelIntensity * (0.12 + reveal * 0.04)
234
+ const halationOpacity = halationIntensity * (0.2 + reveal * 0.08)
235
+ const focusOverlay = interpolate(reveal, [0, 1], [0, 1], {
236
+ easing: Easing.inOut(Easing.quad),
237
+ extrapolateLeft: 'clamp',
238
+ extrapolateRight: 'clamp',
239
+ })
240
+
241
+ const effectLayers = useMemo(
242
+ () => (
243
+ <>
244
+ {glow ? (
245
+ <div
246
+ aria-hidden="true"
247
+ style={{
248
+ position: 'absolute',
249
+ inset: '4%',
250
+ opacity: glowOpacity * 0.55,
251
+ filter: 'blur(20px) saturate(1.18) brightness(0.98)',
252
+ transform: `scale(${1.03 + (1 - animationProgress) * 0.02})`,
253
+ pointerEvents: 'none',
254
+ }}
255
+ >
256
+ <Img
257
+ src={imageSrc}
258
+ alt={title ?? 'Effects photo'}
259
+ style={{
260
+ width: '100%',
261
+ height: '100%',
262
+ objectFit: 'cover',
263
+ }}
264
+ />
265
+ </div>
266
+ ) : null}
267
+ {softFocus ? (
268
+ <div
269
+ aria-hidden="true"
270
+ style={{
271
+ position: 'absolute',
272
+ inset: 0,
273
+ opacity: 0.18 + focusOverlay * 0.08,
274
+ filter: 'blur(10px) saturate(1.04)',
275
+ transform: `scale(${1.02 + focusOverlay * 0.01})`,
276
+ pointerEvents: 'none',
277
+ }}
278
+ >
279
+ <Img
280
+ src={imageSrc}
281
+ alt={title ?? 'Effects photo'}
282
+ style={{
283
+ width: '100%',
284
+ height: '100%',
285
+ objectFit: 'cover',
286
+ }}
287
+ />
288
+ </div>
289
+ ) : null}
290
+ {vignette ? (
291
+ <div
292
+ aria-hidden="true"
293
+ style={{
294
+ position: 'absolute',
295
+ inset: 0,
296
+ background:
297
+ 'radial-gradient(circle at center, rgba(255,255,255,0.04) 0%, rgba(255,255,255,0.01) 28%, rgba(2,6,23,0.14) 56%, rgba(2,6,23,0.46) 100%)',
298
+ opacity: vignetteOpacity * 0.72,
299
+ pointerEvents: 'none',
300
+ }}
301
+ />
302
+ ) : null}
303
+ {warmth ? (
304
+ <div
305
+ aria-hidden="true"
306
+ style={{
307
+ position: 'absolute',
308
+ inset: 0,
309
+ background: `linear-gradient(135deg, ${warmthHue} 0%, rgba(255,255,255,0.02) 36%, ${secondaryAccent ?? 'rgba(59,130,246,0.14)'} 100%)`,
310
+ mixBlendMode: 'screen',
311
+ opacity: 0.08 + focusOverlay * 0.08,
312
+ pointerEvents: 'none',
313
+ }}
314
+ />
315
+ ) : null}
316
+ {grain ? (
317
+ <div
318
+ aria-hidden="true"
319
+ style={{
320
+ position: 'absolute',
321
+ inset: 0,
322
+ opacity: grainOpacity,
323
+ backgroundImage:
324
+ 'radial-gradient(rgba(255,255,255,0.35) 0.7px, transparent 0.7px), radial-gradient(rgba(0,0,0,0.3) 0.7px, transparent 0.7px)',
325
+ backgroundSize: '4px 4px, 4px 4px',
326
+ backgroundPosition: '0 0, 2px 2px',
327
+ mixBlendMode: 'soft-light',
328
+ pointerEvents: 'none',
329
+ }}
330
+ />
331
+ ) : null}
332
+ {hasDuotone ? (
333
+ <div
334
+ aria-hidden="true"
335
+ style={{
336
+ position: 'absolute',
337
+ inset: 0,
338
+ background: `linear-gradient(135deg, ${duotonePrimary} 0%, rgba(255,255,255,0.04) 36%, ${duotoneSecondary} 100%)`,
339
+ mixBlendMode: 'screen',
340
+ opacity: 0.24 + duotoneIntensity * 0.18,
341
+ pointerEvents: 'none',
342
+ }}
343
+ />
344
+ ) : null}
345
+ {hasCoolTone ? (
346
+ <div
347
+ aria-hidden="true"
348
+ style={{
349
+ position: 'absolute',
350
+ inset: 0,
351
+ background: `linear-gradient(180deg, rgba(15,23,42,0.1) 0%, ${coolToneHue} 100%)`,
352
+ mixBlendMode: 'multiply',
353
+ opacity: 0.28 + coolToneIntensity * 0.18,
354
+ pointerEvents: 'none',
355
+ }}
356
+ />
357
+ ) : null}
358
+ {hasLightLeak ? (
359
+ <div
360
+ aria-hidden="true"
361
+ style={{
362
+ position: 'absolute',
363
+ inset: 0,
364
+ background: `radial-gradient(circle at 18% 16%, ${lightLeakHue} 0%, rgba(255,255,255,0.14) 18%, rgba(255,255,255,0.02) 40%, transparent 62%)`,
365
+ mixBlendMode: 'screen',
366
+ opacity: lightLeakOpacity,
367
+ pointerEvents: 'none',
368
+ }}
369
+ />
370
+ ) : null}
371
+ {hasChrome ? (
372
+ <div
373
+ aria-hidden="true"
374
+ style={{
375
+ position: 'absolute',
376
+ inset: 0,
377
+ background: `linear-gradient(140deg, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.06) 28%, ${chromeHue} 48%, rgba(255,255,255,0.02) 78%, rgba(0,0,0,0.18) 100%)`,
378
+ mixBlendMode: 'overlay',
379
+ opacity: chromeOpacity,
380
+ pointerEvents: 'none',
381
+ }}
382
+ />
383
+ ) : null}
384
+ {hasNoir ? (
385
+ <div
386
+ aria-hidden="true"
387
+ style={{
388
+ position: 'absolute',
389
+ inset: 0,
390
+ background: `radial-gradient(circle at center, rgba(255,255,255,0.04) 0%, rgba(255,255,255,0.01) 28%, ${noirHue} 58%, rgba(2,6,23,0.82) 100%)`,
391
+ mixBlendMode: 'multiply',
392
+ opacity: noirOpacity,
393
+ pointerEvents: 'none',
394
+ }}
395
+ />
396
+ ) : null}
397
+ {hasRetro ? (
398
+ <div
399
+ aria-hidden="true"
400
+ style={{
401
+ position: 'absolute',
402
+ inset: 0,
403
+ background: `linear-gradient(135deg, ${retroHue} 0%, rgba(255,255,255,0.03) 34%, #7c3aed 100%)`,
404
+ mixBlendMode: 'screen',
405
+ opacity: retroOpacity,
406
+ pointerEvents: 'none',
407
+ }}
408
+ />
409
+ ) : null}
410
+ {hasInfrared ? (
411
+ <div
412
+ aria-hidden="true"
413
+ style={{
414
+ position: 'absolute',
415
+ inset: 0,
416
+ background: `radial-gradient(circle at 48% 42%, rgba(255,0,96,0.18) 0%, ${infraredHue} 34%, rgba(0,255,170,0.1) 68%, rgba(2,6,23,0.32) 100%)`,
417
+ mixBlendMode: 'screen',
418
+ opacity: infraredOpacity,
419
+ pointerEvents: 'none',
420
+ }}
421
+ />
422
+ ) : null}
423
+ {hasPastel ? (
424
+ <div
425
+ aria-hidden="true"
426
+ style={{
427
+ position: 'absolute',
428
+ inset: 0,
429
+ background: `linear-gradient(180deg, ${pastelHue} 0%, rgba(255,255,255,0.16) 42%, rgba(255,255,255,0.02) 100%)`,
430
+ mixBlendMode: 'soft-light',
431
+ opacity: pastelOpacity,
432
+ pointerEvents: 'none',
433
+ }}
434
+ />
435
+ ) : null}
436
+ {hasHalation ? (
437
+ <div
438
+ aria-hidden="true"
439
+ style={{
440
+ position: 'absolute',
441
+ inset: '1%',
442
+ background:
443
+ `radial-gradient(circle at 50% 36%, ${halationHue} 0%, rgba(255,255,255,0.08) 20%, rgba(255,255,255,0.02) 42%, transparent 70%)`,
444
+ mixBlendMode: 'screen',
445
+ opacity: halationOpacity,
446
+ filter: 'blur(18px)',
447
+ pointerEvents: 'none',
448
+ }}
449
+ />
450
+ ) : null}
451
+ {hasDream ? (
452
+ <div
453
+ aria-hidden="true"
454
+ style={{
455
+ position: 'absolute',
456
+ inset: 0,
457
+ background:
458
+ 'radial-gradient(circle at 50% 50%, rgba(255,255,255,0.18) 0%, rgba(255,255,255,0.08) 28%, rgba(255,255,255,0.02) 58%, rgba(15,23,42,0.12) 100%)',
459
+ mixBlendMode: 'soft-light',
460
+ opacity: dreamOpacity,
461
+ filter: 'blur(8px)',
462
+ pointerEvents: 'none',
463
+ }}
464
+ />
465
+ ) : null}
466
+ </>
467
+ ),
468
+ [
469
+ animationProgress,
470
+ chromeHue,
471
+ chromeOpacity,
472
+ coolToneHue,
473
+ coolToneIntensity,
474
+ focusOverlay,
475
+ dreamIntensity,
476
+ dreamOpacity,
477
+ infraredHue,
478
+ infraredIntensity,
479
+ infraredOpacity,
480
+ duotoneIntensity,
481
+ duotonePrimary,
482
+ duotoneSecondary,
483
+ halationHue,
484
+ halationIntensity,
485
+ halationOpacity,
486
+ grain,
487
+ grainOpacity,
488
+ glow,
489
+ glowOpacity,
490
+ hasChrome,
491
+ hasCoolTone,
492
+ hasDream,
493
+ hasDuotone,
494
+ hasHalation,
495
+ hasLightLeak,
496
+ hasInfrared,
497
+ hasMono,
498
+ hasNoir,
499
+ hasPastel,
500
+ hasRetro,
501
+ hasSepia,
502
+ imageSrc,
503
+ lightLeakHue,
504
+ lightLeakOpacity,
505
+ monoIntensity,
506
+ noirHue,
507
+ noirOpacity,
508
+ secondaryAccent,
509
+ softFocus,
510
+ sepiaIntensity,
511
+ title,
512
+ vignette,
513
+ vignetteOpacity,
514
+ warmth,
515
+ warmthHue,
516
+ vibrantIntensity,
517
+ pastelHue,
518
+ pastelOpacity,
519
+ retroHue,
520
+ retroOpacity,
521
+ ],
522
+ )
523
+
524
+ return (
525
+ <BaseRemotionScene
526
+ id={id ?? sceneId}
527
+ name={name ?? sceneName ?? title}
528
+ style={{
529
+ background:
530
+ portrait
531
+ ? `linear-gradient(180deg, ${accent ?? '#020617'} 0%, #000000 100%)`
532
+ : `radial-gradient(circle at 50% 18%, ${secondaryAccent ?? 'rgba(255,255,255,0.08)'} 0%, ${accent ?? '#020617'} 52%, #000000 100%)`,
533
+ color: textColor ?? '#f8fafc',
534
+ padding: Math.round(runtime.height * (portrait ? 0.02 : 0.03)),
535
+ }}
536
+ >
537
+ <div
538
+ style={{
539
+ position: 'absolute',
540
+ inset: 0,
541
+ overflow: 'hidden',
542
+ border: '1px solid rgba(255,255,255,0.1)',
543
+ background: 'rgba(2,6,23,0.82)',
544
+ isolation: 'isolate',
545
+ }}
546
+ >
547
+ <div
548
+ style={{
549
+ position: 'absolute',
550
+ top: frameTop,
551
+ left: frameLeft,
552
+ width: frameWidth,
553
+ height: frameHeight,
554
+ border: animated ? '1px solid rgba(255,255,255,0.1)' : '1px solid rgba(255,255,255,0.16)',
555
+ boxShadow: animated ? '0 18px 56px rgba(0,0,0,0.24)' : '0 12px 32px rgba(0,0,0,0.14)',
556
+ backgroundColor: animated ? 'rgba(2,6,23,0.14)' : 'rgba(248,250,252,0.06)',
557
+ overflow: 'hidden',
558
+ filter: imageFilter,
559
+ }}
560
+ >
561
+ <Img
562
+ src={imageSrc}
563
+ alt={title ?? 'Effects photo'}
564
+ style={{
565
+ width: '100%',
566
+ height: '100%',
567
+ objectFit: 'cover',
568
+ objectPosition: `${50 + translateX * 0.08}% ${portrait ? 44 : 52}%`,
569
+ transform: `scale(${scale}) translate3d(${translateX}px, ${translateY}px, 0)`,
570
+ transformOrigin: 'center center',
571
+ }}
572
+ />
573
+ </div>
574
+
575
+ <div
576
+ style={{
577
+ position: 'absolute',
578
+ top: frameTop,
579
+ left: frameLeft,
580
+ width: frameWidth,
581
+ height: frameHeight,
582
+ }}
583
+ >
584
+ {effectLayers}
585
+ </div>
586
+
587
+ <div
588
+ aria-hidden="true"
589
+ style={{
590
+ position: 'absolute',
591
+ inset: 0,
592
+ background:
593
+ 'linear-gradient(180deg, rgba(2,6,23,0.04) 0%, rgba(2,6,23,0.12) 38%, rgba(2,6,23,0.52) 100%)',
594
+ pointerEvents: 'none',
595
+ }}
596
+ />
597
+
598
+ <div
599
+ style={{
600
+ position: 'absolute',
601
+ inset: 0,
602
+ display: 'grid',
603
+ alignContent: 'space-between',
604
+ padding: Math.round(runtime.height * (portrait ? 0.02 : 0.03)),
605
+ zIndex: 2,
606
+ pointerEvents: 'none',
607
+ }}
608
+ >
609
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'start', gap: 12 }}>
610
+ <div
611
+ style={{
612
+ display: 'inline-flex',
613
+ alignItems: 'center',
614
+ gap: 8,
615
+ border: '1px solid rgba(255,255,255,0.18)',
616
+ background: 'rgba(2,6,23,0.6)',
617
+ color: '#f8fafc',
618
+ padding: '8px 12px',
619
+ letterSpacing: '0.22em',
620
+ textTransform: 'uppercase',
621
+ fontSize: 11,
622
+ lineHeight: 1,
623
+ }}
624
+ >
625
+ {badge ?? 'Effects Photo'}
626
+ </div>
627
+ </div>
628
+
629
+ <div style={{ display: 'grid', gap: 8, maxWidth: portrait ? '86%' : '58%' }}>
630
+ {title ? <div style={{ fontSize: titleSize, fontWeight: 800, letterSpacing: '-0.06em', lineHeight: 0.94 }}>{title}</div> : null}
631
+ {subtitle ? <div style={{ fontSize: subtitleSize, lineHeight: 1.45, opacity: 0.84 }}>{subtitle}</div> : null}
632
+ </div>
633
+ </div>
634
+ </div>
635
+ </BaseRemotionScene>
636
+ )
637
+ },
638
+ }),
639
+ )
@@ -3,7 +3,7 @@ import { DefaultEffectsPhotoSceneHorizontal } from './default-effects-photo-scen
3
3
  const photoUrl = 'https://heyaai-statics-1342239856.cos.ap-guangzhou.myqcloud.com/tmp/premium_photo-1779404552087-0f905162376f-121.jpeg'
4
4
 
5
5
  const meta = {
6
- title: 'core/scene/photo/effects-photo/DefaultEffectsPhotoSceneHorizontal',
6
+ title: 'core/scene/photo/effects-photo/default-effects-photo-scene-Horizontal/DefaultEffectsPhotoSceneHorizontal',
7
7
  component: DefaultEffectsPhotoSceneHorizontal,
8
8
  args: {
9
9
  title: 'Golden Echo',
@@ -1,20 +1,20 @@
1
- import type { ComponentProps } from 'react'
1
+ import type { DefaultEffectsPhotoSceneProps } from '../default-effects-photo-scene/default-effects-photo-scene'
2
2
 
3
3
  import { VideoComponent, type ScenePluginMetadata } from '@vibecuting/component-project-helper'
4
4
 
5
- import { DefaultEffectsPhotoScene, componentMetadata as baseComponentMetadata } from './default-effects-photo-scene'
5
+ import { DefaultEffectsPhotoScene, componentMetadata as baseComponentMetadata } from '../default-effects-photo-scene/default-effects-photo-scene'
6
6
 
7
7
  export const componentMetadata: ScenePluginMetadata = {
8
8
  ...baseComponentMetadata,
9
9
  name: 'DefaultEffectsPhotoSceneHorizontal',
10
10
  description: 'Photo effects scene for 9:16 portrait previews with a vertical layout',
11
- sourceFile: 'src/core/scene/photo/effects-photo/default-effects-photo-scene-Horizontal.tsx',
11
+ sourceFile: 'src/core/scene/photo/effects-photo/default-effects-photo-scene-Horizontal/default-effects-photo-scene-Horizontal.tsx',
12
12
  aspectRatio: '9:16',
13
13
  tags: Array.from(new Set([...(baseComponentMetadata.tags ?? []), 'horizontal'])),
14
14
  }
15
15
 
16
16
  export const DefaultEffectsPhotoSceneHorizontal = VideoComponent(componentMetadata)(function DefaultEffectsPhotoSceneHorizontal(
17
- props: ComponentProps<typeof DefaultEffectsPhotoScene>,
17
+ props: DefaultEffectsPhotoSceneProps,
18
18
  ) {
19
19
  return <DefaultEffectsPhotoScene {...props} />
20
20
  })