@vibecuting/video-project-core 0.1.26 → 0.1.27

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 (213) hide show
  1. package/package.json +4 -4
  2. package/src/core/intro/_shared/intro-layout.test.ts +18 -0
  3. package/src/core/intro/_shared/intro-layout.ts +50 -0
  4. package/src/core/intro/cyberpunk-intro-holo/default-cyberpunk-intro-bumper-Horizontal.tsx +25 -0
  5. package/src/core/intro/cyberpunk-intro-holo/default-cyberpunk-intro-bumper-Landscape.tsx +25 -0
  6. package/src/core/intro/cyberpunk-intro-holo/default-cyberpunk-intro-bumper.stories.tsx +31 -0
  7. package/src/core/intro/cyberpunk-intro-holo/default-cyberpunk-intro-bumper.tsx +118 -0
  8. package/src/core/intro/cyberpunk-intro-holo/index.ts +11 -0
  9. package/src/core/intro/cyberpunk-intro-neon/default-cyberpunk-intro-bumper-Horizontal.tsx +24 -0
  10. package/src/core/intro/cyberpunk-intro-neon/default-cyberpunk-intro-bumper-Landscape.tsx +24 -0
  11. package/src/core/intro/cyberpunk-intro-neon/default-cyberpunk-intro-bumper.stories.tsx +30 -0
  12. package/src/core/intro/cyberpunk-intro-neon/default-cyberpunk-intro-bumper.tsx +108 -0
  13. package/src/core/intro/cyberpunk-intro-neon/index.ts +10 -0
  14. package/src/core/intro/default-cinematic-intro-bumper/default-cinematic-intro-bumper-Horizontal.tsx +24 -0
  15. package/src/core/intro/default-cinematic-intro-bumper/default-cinematic-intro-bumper-Landscape.tsx +24 -0
  16. package/src/core/intro/default-cinematic-intro-bumper/default-cinematic-intro-bumper.stories.tsx +29 -0
  17. package/src/core/intro/default-cinematic-intro-bumper/default-cinematic-intro-bumper.tsx +234 -0
  18. package/src/core/intro/default-cinematic-intro-bumper/index.ts +11 -0
  19. package/src/core/intro/default-festival-intro-bumper/default-festival-intro-bumper-Horizontal.tsx +24 -0
  20. package/src/core/intro/default-festival-intro-bumper/default-festival-intro-bumper-Landscape.tsx +24 -0
  21. package/src/core/intro/default-festival-intro-bumper/default-festival-intro-bumper.stories.tsx +29 -0
  22. package/src/core/intro/default-festival-intro-bumper/default-festival-intro-bumper.tsx +187 -0
  23. package/src/core/intro/default-festival-intro-bumper/index.ts +11 -0
  24. package/src/core/intro/default-intro-bumper/default-intro-bumper-Horizontal.tsx +24 -0
  25. package/src/core/intro/default-intro-bumper/default-intro-bumper-Landscape.tsx +24 -0
  26. package/src/core/intro/default-intro-bumper/default-intro-bumper.stories.tsx +41 -0
  27. package/src/core/intro/default-intro-bumper/default-intro-bumper.tsx +256 -0
  28. package/src/core/intro/default-intro-bumper/index.ts +11 -0
  29. package/src/core/intro/default-noir-intro-bumper/default-noir-intro-bumper-Horizontal.tsx +24 -0
  30. package/src/core/intro/default-noir-intro-bumper/default-noir-intro-bumper-Landscape.tsx +24 -0
  31. package/src/core/intro/default-noir-intro-bumper/default-noir-intro-bumper.stories.tsx +29 -0
  32. package/src/core/intro/default-noir-intro-bumper/default-noir-intro-bumper.tsx +122 -0
  33. package/src/core/intro/default-noir-intro-bumper/index.ts +11 -0
  34. package/src/core/intro/default-trailer-intro-bumper/default-trailer-intro-bumper-Horizontal.tsx +24 -0
  35. package/src/core/intro/default-trailer-intro-bumper/default-trailer-intro-bumper-Landscape.tsx +24 -0
  36. package/src/core/intro/default-trailer-intro-bumper/default-trailer-intro-bumper.stories.tsx +29 -0
  37. package/src/core/intro/default-trailer-intro-bumper/default-trailer-intro-bumper.tsx +181 -0
  38. package/src/core/intro/default-trailer-intro-bumper/index.ts +11 -0
  39. package/src/core/intro/documentary-intro-observation/default-documentary-intro-bumper-Horizontal.tsx +18 -0
  40. package/src/core/intro/documentary-intro-observation/default-documentary-intro-bumper-Landscape.tsx +18 -0
  41. package/src/core/intro/documentary-intro-observation/default-documentary-intro-bumper.stories.tsx +31 -0
  42. package/src/core/intro/documentary-intro-observation/default-documentary-intro-bumper.tsx +158 -0
  43. package/src/core/intro/documentary-intro-observation/index.ts +10 -0
  44. package/src/core/intro/family-intro-reunion/default-family-intro-bumper-Horizontal.tsx +18 -0
  45. package/src/core/intro/family-intro-reunion/default-family-intro-bumper-Landscape.tsx +18 -0
  46. package/src/core/intro/family-intro-reunion/default-family-intro-bumper.stories.tsx +43 -0
  47. package/src/core/intro/family-intro-reunion/default-family-intro-bumper.tsx +165 -0
  48. package/src/core/intro/family-intro-reunion/index.ts +10 -0
  49. package/src/core/intro/festival-intro-spotlight/default-festival-intro-bumper-Horizontal.tsx +1 -0
  50. package/src/core/intro/festival-intro-spotlight/default-festival-intro-bumper-Landscape.tsx +1 -0
  51. package/src/core/intro/festival-intro-spotlight/default-festival-intro-bumper.stories.tsx +30 -0
  52. package/src/core/intro/festival-intro-spotlight/default-festival-intro-bumper.tsx +105 -0
  53. package/src/core/intro/festival-intro-spotlight/index.ts +10 -0
  54. package/src/core/intro/index.test.ts +45 -0
  55. package/src/core/intro/index.ts +17 -0
  56. package/src/core/intro/noir-intro-city/default-noir-intro-bumper-Horizontal.tsx +24 -0
  57. package/src/core/intro/noir-intro-city/default-noir-intro-bumper-Landscape.tsx +24 -0
  58. package/src/core/intro/noir-intro-city/default-noir-intro-bumper.stories.tsx +31 -0
  59. package/src/core/intro/noir-intro-city/default-noir-intro-bumper.tsx +96 -0
  60. package/src/core/intro/noir-intro-city/index.ts +10 -0
  61. package/src/core/intro/noir-intro-deluxe/default-noir-intro-bumper-Horizontal.tsx +1 -0
  62. package/src/core/intro/noir-intro-deluxe/default-noir-intro-bumper-Landscape.tsx +1 -0
  63. package/src/core/intro/noir-intro-deluxe/default-noir-intro-bumper.stories.tsx +31 -0
  64. package/src/core/intro/noir-intro-deluxe/default-noir-intro-bumper.tsx +117 -0
  65. package/src/core/intro/noir-intro-deluxe/index.ts +10 -0
  66. package/src/core/intro/sci-fi-intro/default-sci-fi-intro-bumper-Horizontal.tsx +1 -0
  67. package/src/core/intro/sci-fi-intro/default-sci-fi-intro-bumper-Landscape.tsx +1 -0
  68. package/src/core/intro/sci-fi-intro/default-sci-fi-intro-bumper.stories.tsx +48 -0
  69. package/src/core/intro/sci-fi-intro/default-sci-fi-intro-bumper.tsx +105 -0
  70. package/src/core/intro/sci-fi-intro/index.ts +10 -0
  71. package/src/core/intro/thriller-intro-suspense/default-thriller-intro-bumper-Horizontal.tsx +18 -0
  72. package/src/core/intro/thriller-intro-suspense/default-thriller-intro-bumper-Landscape.tsx +18 -0
  73. package/src/core/intro/thriller-intro-suspense/default-thriller-intro-bumper.stories.tsx +31 -0
  74. package/src/core/intro/thriller-intro-suspense/default-thriller-intro-bumper.tsx +155 -0
  75. package/src/core/intro/thriller-intro-suspense/index.ts +10 -0
  76. package/src/core/intro/trailer-intro-premiere/default-trailer-intro-bumper-Horizontal.tsx +1 -0
  77. package/src/core/intro/trailer-intro-premiere/default-trailer-intro-bumper-Landscape.tsx +1 -0
  78. package/src/core/intro/trailer-intro-premiere/default-trailer-intro-bumper.stories.tsx +30 -0
  79. package/src/core/intro/trailer-intro-premiere/default-trailer-intro-bumper.tsx +104 -0
  80. package/src/core/intro/trailer-intro-premiere/index.ts +10 -0
  81. package/src/core/intro/travel-intro-journey/default-travel-intro-bumper-Horizontal.tsx +18 -0
  82. package/src/core/intro/travel-intro-journey/default-travel-intro-bumper-Landscape.tsx +18 -0
  83. package/src/core/intro/travel-intro-journey/default-travel-intro-bumper.stories.tsx +43 -0
  84. package/src/core/intro/travel-intro-journey/default-travel-intro-bumper.tsx +158 -0
  85. package/src/core/intro/travel-intro-journey/index.ts +10 -0
  86. package/src/core/intro/western-intro/default-western-intro-bumper-Horizontal.tsx +24 -0
  87. package/src/core/intro/western-intro/default-western-intro-bumper-Landscape.tsx +24 -0
  88. package/src/core/intro/western-intro/default-western-intro-bumper.stories.tsx +29 -0
  89. package/src/core/intro/western-intro/default-western-intro-bumper.tsx +146 -0
  90. package/src/core/intro/western-intro/index.ts +4 -0
  91. package/src/core/intro/western-intro-gangster/default-western-intro-bumper-Horizontal.tsx +25 -0
  92. package/src/core/intro/western-intro-gangster/default-western-intro-bumper-Landscape.tsx +25 -0
  93. package/src/core/intro/western-intro-gangster/default-western-intro-bumper.stories.tsx +31 -0
  94. package/src/core/intro/western-intro-gangster/default-western-intro-bumper.tsx +105 -0
  95. package/src/core/intro/western-intro-gangster/index.ts +11 -0
  96. package/src/core/outro/_shared/outro-layout.test.ts +32 -0
  97. package/src/core/outro/_shared/outro-layout.ts +72 -0
  98. package/src/core/outro/award-outro-celebration/default-award-outro-bumper-Horizontal.tsx +18 -0
  99. package/src/core/outro/award-outro-celebration/default-award-outro-bumper-Landscape.tsx +18 -0
  100. package/src/core/outro/award-outro-celebration/default-award-outro-bumper.stories.tsx +42 -0
  101. package/src/core/outro/award-outro-celebration/default-award-outro-bumper.tsx +152 -0
  102. package/src/core/outro/award-outro-celebration/index.ts +10 -0
  103. package/src/core/outro/blackout-outro-finale/default-blackout-outro-bumper-Horizontal.tsx +1 -0
  104. package/src/core/outro/blackout-outro-finale/default-blackout-outro-bumper-Landscape.tsx +1 -0
  105. package/src/core/outro/blackout-outro-finale/default-blackout-outro-bumper.stories.tsx +28 -0
  106. package/src/core/outro/blackout-outro-finale/default-blackout-outro-bumper.tsx +71 -0
  107. package/src/core/outro/blackout-outro-finale/index.ts +10 -0
  108. package/src/core/outro/credits-roll-outro-epic/default-credits-roll-outro-Horizontal.tsx +24 -0
  109. package/src/core/outro/credits-roll-outro-epic/default-credits-roll-outro-Landscape.tsx +24 -0
  110. package/src/core/outro/credits-roll-outro-epic/default-credits-roll-outro.stories.tsx +31 -0
  111. package/src/core/outro/credits-roll-outro-epic/default-credits-roll-outro.tsx +106 -0
  112. package/src/core/outro/credits-roll-outro-epic/index.ts +10 -0
  113. package/src/core/outro/credits-roll-outro-premium/default-credits-roll-outro-Horizontal.tsx +1 -0
  114. package/src/core/outro/credits-roll-outro-premium/default-credits-roll-outro-Landscape.tsx +1 -0
  115. package/src/core/outro/credits-roll-outro-premium/default-credits-roll-outro.stories.tsx +30 -0
  116. package/src/core/outro/credits-roll-outro-premium/default-credits-roll-outro.tsx +88 -0
  117. package/src/core/outro/credits-roll-outro-premium/index.ts +10 -0
  118. package/src/core/outro/credits-roll-outro-royal/default-credits-roll-outro-Horizontal.tsx +25 -0
  119. package/src/core/outro/credits-roll-outro-royal/default-credits-roll-outro-Landscape.tsx +25 -0
  120. package/src/core/outro/credits-roll-outro-royal/default-credits-roll-outro.stories.tsx +32 -0
  121. package/src/core/outro/credits-roll-outro-royal/default-credits-roll-outro.tsx +110 -0
  122. package/src/core/outro/credits-roll-outro-royal/index.ts +11 -0
  123. package/src/core/outro/default-blackout-outro-bumper/default-blackout-outro-bumper-Horizontal.tsx +22 -0
  124. package/src/core/outro/default-blackout-outro-bumper/default-blackout-outro-bumper-Landscape.tsx +22 -0
  125. package/src/core/outro/default-blackout-outro-bumper/default-blackout-outro-bumper.stories.tsx +48 -0
  126. package/src/core/outro/default-blackout-outro-bumper/default-blackout-outro-bumper.tsx +124 -0
  127. package/src/core/outro/default-blackout-outro-bumper/index.ts +11 -0
  128. package/src/core/outro/default-credits-roll-outro/default-credits-roll-outro-Horizontal.tsx +22 -0
  129. package/src/core/outro/default-credits-roll-outro/default-credits-roll-outro-Landscape.tsx +22 -0
  130. package/src/core/outro/default-credits-roll-outro/default-credits-roll-outro.stories.tsx +48 -0
  131. package/src/core/outro/default-credits-roll-outro/default-credits-roll-outro.tsx +208 -0
  132. package/src/core/outro/default-credits-roll-outro/index.ts +11 -0
  133. package/src/core/outro/default-epilogue-outro/default-epilogue-outro-Horizontal.tsx +22 -0
  134. package/src/core/outro/default-epilogue-outro/default-epilogue-outro-Landscape.tsx +22 -0
  135. package/src/core/outro/default-epilogue-outro/default-epilogue-outro.stories.tsx +48 -0
  136. package/src/core/outro/default-epilogue-outro/default-epilogue-outro.tsx +115 -0
  137. package/src/core/outro/default-epilogue-outro/index.ts +11 -0
  138. package/src/core/outro/default-outro-bumper/default-outro-bumper-Horizontal.tsx +22 -0
  139. package/src/core/outro/default-outro-bumper/default-outro-bumper-Landscape.tsx +22 -0
  140. package/src/core/outro/default-outro-bumper/default-outro-bumper.stories.tsx +48 -0
  141. package/src/core/outro/default-outro-bumper/default-outro-bumper.tsx +159 -0
  142. package/src/core/outro/default-outro-bumper/index.ts +11 -0
  143. package/src/core/outro/default-sunset-outro-bumper/default-sunset-outro-bumper-Horizontal.tsx +22 -0
  144. package/src/core/outro/default-sunset-outro-bumper/default-sunset-outro-bumper-Landscape.tsx +22 -0
  145. package/src/core/outro/default-sunset-outro-bumper/default-sunset-outro-bumper.stories.tsx +48 -0
  146. package/src/core/outro/default-sunset-outro-bumper/default-sunset-outro-bumper.tsx +183 -0
  147. package/src/core/outro/default-sunset-outro-bumper/index.ts +11 -0
  148. package/src/core/outro/festival-outro-encore/default-festival-outro-bumper-Horizontal.tsx +18 -0
  149. package/src/core/outro/festival-outro-encore/default-festival-outro-bumper-Landscape.tsx +18 -0
  150. package/src/core/outro/festival-outro-encore/default-festival-outro-bumper.stories.tsx +31 -0
  151. package/src/core/outro/festival-outro-encore/default-festival-outro-bumper.tsx +130 -0
  152. package/src/core/outro/festival-outro-encore/index.ts +10 -0
  153. package/src/core/outro/heist-outro/default-heist-outro-bumper-Horizontal.tsx +24 -0
  154. package/src/core/outro/heist-outro/default-heist-outro-bumper-Landscape.tsx +24 -0
  155. package/src/core/outro/heist-outro/default-heist-outro-bumper.stories.tsx +29 -0
  156. package/src/core/outro/heist-outro/default-heist-outro-bumper.tsx +160 -0
  157. package/src/core/outro/heist-outro/index.ts +4 -0
  158. package/src/core/outro/index.test.ts +88 -0
  159. package/src/core/outro/index.ts +73 -0
  160. package/src/core/outro/memoir-outro-reflection/default-memoir-outro-bumper-Horizontal.tsx +18 -0
  161. package/src/core/outro/memoir-outro-reflection/default-memoir-outro-bumper-Landscape.tsx +18 -0
  162. package/src/core/outro/memoir-outro-reflection/default-memoir-outro-bumper.stories.tsx +42 -0
  163. package/src/core/outro/memoir-outro-reflection/default-memoir-outro-bumper.tsx +158 -0
  164. package/src/core/outro/memoir-outro-reflection/index.ts +10 -0
  165. package/src/core/outro/romance-outro/default-romance-outro-bumper-Horizontal.tsx +1 -0
  166. package/src/core/outro/romance-outro/default-romance-outro-bumper-Landscape.tsx +1 -0
  167. package/src/core/outro/romance-outro/default-romance-outro-bumper.stories.tsx +48 -0
  168. package/src/core/outro/romance-outro/default-romance-outro-bumper.tsx +123 -0
  169. package/src/core/outro/romance-outro/index.ts +10 -0
  170. package/src/core/outro/sunset-outro-coda/default-sunset-outro-bumper-Horizontal.tsx +1 -0
  171. package/src/core/outro/sunset-outro-coda/default-sunset-outro-bumper-Landscape.tsx +1 -0
  172. package/src/core/outro/sunset-outro-coda/default-sunset-outro-bumper.stories.tsx +30 -0
  173. package/src/core/outro/sunset-outro-coda/default-sunset-outro-bumper.tsx +75 -0
  174. package/src/core/outro/sunset-outro-coda/index.ts +10 -0
  175. package/src/core/scene/slide/_shared/index.ts +27 -0
  176. package/src/core/scene/slide/_shared/media-templates.test.ts +47 -0
  177. package/src/core/scene/slide/_shared/media-templates.tsx +324 -0
  178. package/src/core/scene/slide/index.test.ts +28 -0
  179. package/src/core/scene/slide/index.ts +14 -0
  180. package/src/core/scene/slide/person-intro/default-person-intro-duo-slide.tsx +19 -0
  181. package/src/core/scene/slide/person-intro/default-person-intro-group-slide.tsx +168 -0
  182. package/src/core/scene/slide/person-intro/default-person-intro-quad-slide.tsx +19 -0
  183. package/src/core/scene/slide/person-intro/default-person-intro-slide-Horizontal.animated.stories.tsx +47 -0
  184. package/src/core/scene/slide/person-intro/default-person-intro-slide-Horizontal.stories.tsx +46 -0
  185. package/src/core/scene/slide/person-intro/default-person-intro-slide-Horizontal.tsx +302 -0
  186. package/src/core/scene/slide/person-intro/default-person-intro-slide-Landscape.tsx +20 -0
  187. package/src/core/scene/slide/person-intro/default-person-intro-slide.animated.stories.tsx +126 -0
  188. package/src/core/scene/slide/person-intro/default-person-intro-slide.stories.tsx +119 -0
  189. package/src/core/scene/slide/person-intro/default-person-intro-slide.tsx +363 -0
  190. package/src/core/scene/slide/person-intro/default-person-intro-trio-slide.tsx +19 -0
  191. package/src/core/scene/slide/person-intro/index.ts +8 -0
  192. package/src/core/scene/slide/photo-album/default-photo-album-multi-slide.tsx +19 -0
  193. package/src/core/scene/slide/photo-album/default-photo-album-pair-slide.tsx +19 -0
  194. package/src/core/scene/slide/photo-album/default-photo-album-single-slide.tsx +19 -0
  195. package/src/core/scene/slide/photo-album/default-photo-album-slide-Horizontal.animated.stories.tsx +26 -0
  196. package/src/core/scene/slide/photo-album/default-photo-album-slide-Horizontal.stories.tsx +25 -0
  197. package/src/core/scene/slide/photo-album/default-photo-album-slide-Horizontal.tsx +20 -0
  198. package/src/core/scene/slide/photo-album/default-photo-album-slide-Landscape.tsx +20 -0
  199. package/src/core/scene/slide/photo-album/default-photo-album-slide.animated.stories.tsx +94 -0
  200. package/src/core/scene/slide/photo-album/default-photo-album-slide.stories.tsx +87 -0
  201. package/src/core/scene/slide/photo-album/default-photo-album-slide.tsx +414 -0
  202. package/src/core/scene/slide/photo-album/index.ts +7 -0
  203. package/src/core/scene/slide/video-showcase/default-video-showcase-multi-slide.tsx +195 -0
  204. package/src/core/scene/slide/video-showcase/default-video-showcase-slide-Horizontal.tsx +212 -0
  205. package/src/core/scene/slide/video-showcase/default-video-showcase-slide-Landscape.tsx +20 -0
  206. package/src/core/scene/slide/video-showcase/default-video-showcase-slide.animated.stories.tsx +78 -0
  207. package/src/core/scene/slide/video-showcase/default-video-showcase-slide.stories.tsx +74 -0
  208. package/src/core/scene/slide/video-showcase/default-video-showcase-slide.tsx +365 -0
  209. package/src/core/scene/slide/video-showcase/index.ts +5 -0
  210. package/src/core/intro/default-intro-bumper.stories.tsx +0 -19
  211. package/src/core/intro/default-intro-bumper.tsx +0 -218
  212. package/src/core/outro/default-outro-bumper.stories.tsx +0 -19
  213. package/src/core/outro/default-outro-bumper.tsx +0 -218
@@ -0,0 +1,195 @@
1
+ import type { ReactNode } from 'react'
2
+
3
+ import { z } from 'zod'
4
+
5
+ import { VideoComponent, defineScenePluginMetadata } from '@vibecuting/component-project-helper'
6
+
7
+ import { SceneMotionLayer, useRemotionSceneRuntime } from '../../../../base'
8
+ import { defineSceneComponent } from '../../../../plugins/scene-component'
9
+ import type { DefaultSceneProps } from '../../../../scenes/default-scene-props'
10
+ import { SlideFrame, getOverflowSafeSlideGridLayout, getSlideTypographyScale } from '../_shared'
11
+
12
+ export interface DefaultVideoShowcaseMultiClip {
13
+ title: string
14
+ caption?: string
15
+ duration?: string
16
+ poster?: ReactNode
17
+ }
18
+
19
+ export interface DefaultVideoShowcaseMultiSlideProps extends DefaultSceneProps {
20
+ title: string
21
+ subtitle?: string
22
+ clips: DefaultVideoShowcaseMultiClip[]
23
+ }
24
+
25
+ function MultiClipCard({
26
+ clip,
27
+ scale,
28
+ index,
29
+ }: {
30
+ clip: DefaultVideoShowcaseMultiClip
31
+ scale: ReturnType<typeof getSlideTypographyScale>
32
+ index: number
33
+ }) {
34
+ return (
35
+ <article
36
+ style={{
37
+ minWidth: 0,
38
+ minHeight: 0,
39
+ overflow: 'hidden',
40
+ border: '1px solid rgba(148,163,184,0.18)',
41
+ background: 'rgba(15,23,42,0.34)',
42
+ }}
43
+ >
44
+ <div
45
+ style={{
46
+ position: 'relative',
47
+ aspectRatio: '16 / 9',
48
+ background: 'linear-gradient(135deg, rgba(15,23,42,0.96), rgba(30,41,59,0.96))',
49
+ overflow: 'hidden',
50
+ }}
51
+ >
52
+ <div style={{ position: 'absolute', inset: 0, display: 'grid', placeItems: 'center', color: '#f8fafc', opacity: 0.92 }}>
53
+ {clip.poster ?? <div style={{ fontSize: 36, fontWeight: 800, letterSpacing: '-0.06em' }}>▶</div>}
54
+ </div>
55
+ <div
56
+ style={{
57
+ position: 'absolute',
58
+ inset: 0,
59
+ background:
60
+ 'linear-gradient(180deg, rgba(2,6,23,0.12) 0%, rgba(2,6,23,0.22) 38%, rgba(2,6,23,0.84) 100%)',
61
+ }}
62
+ />
63
+ <span
64
+ style={{
65
+ position: 'absolute',
66
+ left: 12,
67
+ top: 12,
68
+ zIndex: 1,
69
+ padding: '6px 10px',
70
+ border: '1px solid rgba(255,255,255,0.18)',
71
+ background: 'rgba(2,6,23,0.38)',
72
+ color: '#f8fafc',
73
+ fontSize: scale.caption,
74
+ letterSpacing: '0.18em',
75
+ textTransform: 'uppercase',
76
+ }}
77
+ >
78
+ {String(index + 1).padStart(2, '0')}
79
+ </span>
80
+ </div>
81
+
82
+ <div style={{ padding: 16, display: 'grid', gap: 8, color: '#e2e8f0' }}>
83
+ <div style={{ fontSize: scale.body * 0.94, fontWeight: 700, lineHeight: 1.15, letterSpacing: '-0.03em' }}>{clip.title}</div>
84
+ {clip.caption ? <div style={{ fontSize: scale.caption, lineHeight: 1.45, opacity: 0.78 }}>{clip.caption}</div> : null}
85
+ {clip.duration ? (
86
+ <div style={{ fontSize: scale.caption, letterSpacing: '0.16em', textTransform: 'uppercase', opacity: 0.62 }}>{clip.duration}</div>
87
+ ) : null}
88
+ </div>
89
+ </article>
90
+ )
91
+ }
92
+
93
+ export const componentMetadata = defineScenePluginMetadata({
94
+ resourceKind: 'scene',
95
+ name: 'DefaultVideoShowcaseMultiSlide',
96
+ description: 'Multi video showcase slide',
97
+ sourceFile: 'src/core/scene/slide/video-showcase/default-video-showcase-multi-slide.tsx',
98
+ pluginKey: 'core.slide.video-showcase.multi',
99
+ tags: ['scene', 'slide', 'video', 'showcase', 'multi'],
100
+ aspectRatio: '16:9',
101
+ sceneType: 'scene',
102
+ sceneFamily: 'slide',
103
+ rootLayout: 'absolute-fill',
104
+ propsTypeName: 'DefaultVideoShowcaseMultiSlideProps',
105
+ })
106
+
107
+ export const DefaultVideoShowcaseMultiSlide = VideoComponent(componentMetadata)(
108
+ defineSceneComponent({
109
+ family: 'slide',
110
+ propsSchema: z.object({
111
+ sceneId: z.string().optional(),
112
+ sceneName: z.string().optional(),
113
+ title: z.string().min(1),
114
+ subtitle: z.string().optional(),
115
+ clips: z
116
+ .array(
117
+ z.object({
118
+ title: z.string().min(1),
119
+ caption: z.string().optional(),
120
+ duration: z.string().optional(),
121
+ poster: z.any().optional(),
122
+ }),
123
+ )
124
+ .min(2),
125
+ }),
126
+ component: function DefaultVideoShowcaseMultiSlide({ sceneId, sceneName, title, subtitle, clips }: DefaultVideoShowcaseMultiSlideProps) {
127
+ const runtime = useRemotionSceneRuntime()
128
+ const scale = getSlideTypographyScale(runtime.height)
129
+ const isPortrait = runtime.height > runtime.width
130
+ const grid = getOverflowSafeSlideGridLayout(clips.length, isPortrait ? 2 : 3, {
131
+ runtimeWidth: runtime.width,
132
+ reservedWidth: isPortrait ? 40 : 128,
133
+ runtimeHeight: runtime.height,
134
+ reservedHeight: isPortrait ? 420 : 240,
135
+ minCardWidth: isPortrait ? 180 : 220,
136
+ minCardHeight: isPortrait ? 180 : 210,
137
+ })
138
+
139
+ return (
140
+ <SlideFrame
141
+ pluginKey={componentMetadata.pluginKey}
142
+ sceneId={sceneId}
143
+ sceneName={sceneName ?? title}
144
+ background="linear-gradient(135deg, #020617 0%, #0f172a 56%, #1d4ed8 100%)"
145
+ >
146
+ <section
147
+ style={{
148
+ width: '100%',
149
+ height: '100%',
150
+ display: 'grid',
151
+ gridTemplateColumns: isPortrait ? '1fr' : 'minmax(280px, 0.88fr) minmax(0, 1.12fr)',
152
+ gap: isPortrait ? 18 : 28,
153
+ padding: isPortrait ? '40px 24px 42px' : '64px 72px',
154
+ color: '#e2e8f0',
155
+ minWidth: 0,
156
+ minHeight: 0,
157
+ }}
158
+ >
159
+ <SceneMotionLayer variant="hero-title">
160
+ <div style={{ display: 'grid', alignContent: 'start', gap: 14, minWidth: 0 }}>
161
+ <div style={{ fontSize: scale.eyebrow, letterSpacing: '0.2em', textTransform: 'uppercase', opacity: 0.72 }}>Video wall</div>
162
+ <h1 style={{ margin: 0, fontSize: isPortrait ? scale.title * 0.78 : scale.title, lineHeight: 0.94, letterSpacing: '-0.06em' }}>{title}</h1>
163
+ {subtitle ? (
164
+ <p style={{ margin: 0, fontSize: isPortrait ? scale.body * 0.92 : scale.body, lineHeight: 1.5, opacity: 0.82, maxWidth: 560 }}>{subtitle}</p>
165
+ ) : null}
166
+ <div style={{ fontSize: scale.caption, letterSpacing: '0.18em', textTransform: 'uppercase', opacity: 0.56 }}>
167
+ {clips.length} clips
168
+ </div>
169
+ </div>
170
+ </SceneMotionLayer>
171
+
172
+ <SceneMotionLayer variant="panel" delayIndex={1}>
173
+ <div
174
+ style={{
175
+ height: '100%',
176
+ minWidth: 0,
177
+ minHeight: 0,
178
+ display: 'grid',
179
+ gridTemplateColumns: `repeat(${Math.max(1, grid.columns)}, minmax(0, 1fr))`,
180
+ gap: grid.gap,
181
+ }}
182
+ >
183
+ {clips.slice(0, 6).map((clip, index) => (
184
+ <SceneMotionLayer key={`${clip.title}-${index}`} variant="card" delayIndex={index + 1}>
185
+ <MultiClipCard clip={clip} index={index} scale={scale} />
186
+ </SceneMotionLayer>
187
+ ))}
188
+ </div>
189
+ </SceneMotionLayer>
190
+ </section>
191
+ </SlideFrame>
192
+ )
193
+ },
194
+ }),
195
+ )
@@ -0,0 +1,212 @@
1
+ import type { ReactNode } from 'react'
2
+
3
+ import { z } from 'zod'
4
+
5
+ import { VideoComponent, defineScenePluginMetadata } from '@vibecuting/component-project-helper'
6
+
7
+ import { defineSceneComponent } from '../../../../plugins/scene-component'
8
+ import { SceneMotionLayer, useRemotionSceneRuntime } from '../../../../base'
9
+ import type { DefaultSceneProps } from '../../../../scenes/default-scene-props'
10
+ import { SlideFrame, getSlideTypographyScale } from '../_shared'
11
+ import { componentMetadata as baseComponentMetadata } from './default-video-showcase-slide'
12
+
13
+ export interface DefaultVideoShowcaseSlideHorizontalProps extends DefaultSceneProps {
14
+ title: string
15
+ subtitle?: string
16
+ chapter?: string
17
+ runtimeLabel?: string
18
+ posterLabel?: string
19
+ posterCaption?: string
20
+ notes?: string[]
21
+ poster?: ReactNode
22
+ }
23
+
24
+ export const componentMetadata = defineScenePluginMetadata({
25
+ ...baseComponentMetadata,
26
+ name: 'DefaultVideoShowcaseSlideHorizontal',
27
+ description: 'Video showcase slide (Portrait 9:16 variant)',
28
+ sourceFile: 'src/core/scene/slide/video-showcase/default-video-showcase-slide-Horizontal.tsx',
29
+ aspectRatio: '9:16',
30
+ tags: Array.from(new Set([...(baseComponentMetadata.tags ?? []), 'horizontal'])),
31
+ })
32
+
33
+ export const DefaultVideoShowcaseSlideHorizontal = VideoComponent(componentMetadata)(
34
+ defineSceneComponent({
35
+ family: 'slide',
36
+ propsSchema: z.object({
37
+ sceneId: z.string().optional(),
38
+ sceneName: z.string().optional(),
39
+ title: z.string().min(1),
40
+ subtitle: z.string().optional(),
41
+ chapter: z.string().optional(),
42
+ runtimeLabel: z.string().optional(),
43
+ posterLabel: z.string().optional(),
44
+ posterCaption: z.string().optional(),
45
+ notes: z.array(z.string().min(1)).max(5).optional(),
46
+ poster: z.any().optional(),
47
+ }),
48
+ component: function DefaultVideoShowcaseSlideHorizontal({
49
+ sceneId,
50
+ sceneName,
51
+ title,
52
+ subtitle,
53
+ chapter,
54
+ runtimeLabel,
55
+ posterLabel,
56
+ posterCaption,
57
+ notes,
58
+ poster,
59
+ }: DefaultVideoShowcaseSlideHorizontalProps) {
60
+ const runtime = useRemotionSceneRuntime()
61
+ const scale = getSlideTypographyScale(runtime.height)
62
+
63
+ return (
64
+ <SlideFrame
65
+ pluginKey={componentMetadata.pluginKey}
66
+ sceneId={sceneId}
67
+ sceneName={sceneName ?? title}
68
+ background="linear-gradient(180deg, #020617 0%, #0f172a 52%, #1d4ed8 100%)"
69
+ >
70
+ <section
71
+ style={{
72
+ width: '100%',
73
+ height: '100%',
74
+ display: 'grid',
75
+ gridTemplateRows: 'auto auto 1fr',
76
+ gap: 18,
77
+ padding: '34px 24px 36px',
78
+ color: '#e2e8f0',
79
+ justifyItems: 'center',
80
+ alignContent: 'start',
81
+ }}
82
+ >
83
+ <SceneMotionLayer variant="panel">
84
+ <div
85
+ style={{
86
+ position: 'relative',
87
+ width: 'min(100%, 400px)',
88
+ aspectRatio: '4 / 5',
89
+ overflow: 'hidden',
90
+ borderRadius: 0,
91
+ border: '1px solid rgba(148,163,184,0.22)',
92
+ background: 'linear-gradient(135deg, rgba(15,23,42,0.96) 0%, rgba(30,41,59,0.92) 42%, rgba(37,99,235,0.78) 100%)',
93
+ boxShadow: '0 22px 54px rgba(15,23,42,0.28)',
94
+ }}
95
+ >
96
+ <div
97
+ style={{
98
+ position: 'absolute',
99
+ inset: 0,
100
+ background:
101
+ 'radial-gradient(circle at 25% 18%, rgba(96,165,250,0.34), transparent 28%), radial-gradient(circle at 80% 22%, rgba(56,189,248,0.16), transparent 22%), linear-gradient(180deg, rgba(2,6,23,0.14) 0%, rgba(2,6,23,0.76) 100%)',
102
+ }}
103
+ />
104
+ <div style={{ position: 'absolute', inset: 14, border: '1px solid rgba(255,255,255,0.12)', pointerEvents: 'none' }} />
105
+ <div style={{ position: 'relative', zIndex: 1, width: '100%', height: '100%', padding: 16, display: 'grid', gridTemplateRows: 'auto 1fr auto', gap: 12 }}>
106
+ <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10 }}>
107
+ <div style={{ display: 'inline-flex', alignItems: 'center', gap: 8, padding: '7px 10px', border: '1px solid rgba(255,255,255,0.16)', background: 'rgba(15,23,42,0.46)', fontSize: scale.caption, letterSpacing: '0.16em', textTransform: 'uppercase' }}>
108
+ <span style={{ width: 8, height: 8, background: '#38bdf8', display: 'inline-block' }} />
109
+ {posterLabel ?? 'Poster'}
110
+ </div>
111
+ {runtimeLabel ? (
112
+ <div style={{ display: 'inline-flex', alignItems: 'center', padding: '7px 10px', border: '1px solid rgba(255,255,255,0.16)', background: 'rgba(2,6,23,0.5)', fontSize: scale.caption, fontWeight: 700 }}>
113
+ {runtimeLabel}
114
+ </div>
115
+ ) : null}
116
+ </div>
117
+
118
+ <div style={{ display: 'grid', placeItems: 'center', minHeight: 0 }}>
119
+ {poster ?? (
120
+ <div style={{ display: 'grid', placeItems: 'center', gap: 14, textAlign: 'center' }}>
121
+ <div style={{ width: 86, height: 86, display: 'grid', placeItems: 'center', borderRadius: '999px', background: 'rgba(15,23,42,0.64)', border: '1px solid rgba(255,255,255,0.18)', boxShadow: '0 12px 32px rgba(15,23,42,0.28)', fontSize: 28 }}>
122
+
123
+ </div>
124
+ <div>
125
+ <div style={{ fontSize: scale.body * 0.94, fontWeight: 700 }}>{posterLabel ?? 'Video poster'}</div>
126
+ <div style={{ marginTop: 8, fontSize: scale.caption, letterSpacing: '0.14em', textTransform: 'uppercase', opacity: 0.68 }}>
127
+ {posterCaption ?? 'A true portrait poster composition for mobile-first previews.'}
128
+ </div>
129
+ </div>
130
+ </div>
131
+ )}
132
+ </div>
133
+
134
+ <div style={{ display: 'grid', gap: 8 }}>
135
+ <div style={{ fontSize: scale.caption, letterSpacing: '0.2em', textTransform: 'uppercase', opacity: 0.72 }}>{chapter ?? 'Video showcase'}</div>
136
+ <div style={{ fontSize: scale.body * 0.9, lineHeight: 1.38, opacity: 0.86 }}>{posterCaption ?? 'Stacked composition for the clip poster, runtime and supporting context.'}</div>
137
+ </div>
138
+ </div>
139
+ </div>
140
+ </SceneMotionLayer>
141
+
142
+ <div style={{ width: 'min(100%, 460px)', display: 'grid', gap: 14 }}>
143
+ <SceneMotionLayer variant="hero-copy">
144
+ <div
145
+ style={{
146
+ display: 'inline-flex',
147
+ alignItems: 'center',
148
+ gap: 10,
149
+ padding: '8px 12px',
150
+ border: '1px solid rgba(148,163,184,0.2)',
151
+ background: 'rgba(15,23,42,0.42)',
152
+ fontSize: scale.caption,
153
+ letterSpacing: '0.18em',
154
+ textTransform: 'uppercase',
155
+ width: 'fit-content',
156
+ }}
157
+ >
158
+ <span style={{ width: 8, height: 8, background: '#38bdf8', display: 'inline-block' }} />
159
+ {chapter ?? 'Video showcase'}
160
+ </div>
161
+ </SceneMotionLayer>
162
+
163
+ <SceneMotionLayer variant="hero-title" delayIndex={1}>
164
+ <h1 style={{ margin: 0, fontSize: scale.title * 0.76, lineHeight: 0.94, letterSpacing: '-0.06em', textAlign: 'left' }}>{title}</h1>
165
+ </SceneMotionLayer>
166
+
167
+ {subtitle ? (
168
+ <SceneMotionLayer variant="hero-copy" delayIndex={2}>
169
+ <p style={{ margin: 0, fontSize: scale.body * 0.88, lineHeight: 1.5, opacity: 0.82 }}>{subtitle}</p>
170
+ </SceneMotionLayer>
171
+ ) : null}
172
+ </div>
173
+
174
+ <SceneMotionLayer variant="panel" delayIndex={3}>
175
+ <div style={{ width: 'min(100%, 460px)', display: 'grid', gap: 12, gridTemplateColumns: 'repeat(2, minmax(0, 1fr))' }}>
176
+ <article style={{ padding: '14px 14px 15px', borderRadius: 0, border: '1px solid rgba(148,163,184,0.18)', background: 'rgba(15,23,42,0.24)' }}>
177
+ <div style={{ fontSize: scale.caption, letterSpacing: '0.24em', textTransform: 'uppercase', opacity: 0.58 }}>Chapter</div>
178
+ <div style={{ marginTop: 8, fontSize: scale.body * 0.88, lineHeight: 1.32, fontWeight: 700 }}>{chapter ?? 'Opening sequence'}</div>
179
+ </article>
180
+ <article style={{ padding: '14px 14px 15px', borderRadius: 0, border: '1px solid rgba(148,163,184,0.18)', background: 'rgba(15,23,42,0.24)' }}>
181
+ <div style={{ fontSize: scale.caption, letterSpacing: '0.24em', textTransform: 'uppercase', opacity: 0.58 }}>Runtime</div>
182
+ <div style={{ marginTop: 8, fontSize: scale.body * 0.88, lineHeight: 1.32, fontWeight: 700 }}>{runtimeLabel ?? '02:34'}</div>
183
+ </article>
184
+ </div>
185
+ </SceneMotionLayer>
186
+
187
+ <SceneMotionLayer variant="panel" delayIndex={4}>
188
+ <div style={{ width: 'min(100%, 460px)', display: 'grid', gap: 10 }}>
189
+ {(notes ?? []).slice(0, 5).map((note, index) => (
190
+ <article
191
+ key={`${index}-${note}`}
192
+ style={{
193
+ padding: '13px 14px',
194
+ borderRadius: 0,
195
+ border: '1px solid rgba(148,163,184,0.18)',
196
+ background: 'rgba(15,23,42,0.22)',
197
+ }}
198
+ >
199
+ <div style={{ fontSize: scale.caption, letterSpacing: '0.2em', textTransform: 'uppercase', opacity: 0.58 }}>
200
+ Note {String(index + 1).padStart(2, '0')}
201
+ </div>
202
+ <p style={{ margin: '8px 0 0', fontSize: scale.body * 0.84, lineHeight: 1.42, opacity: 0.92 }}>{note}</p>
203
+ </article>
204
+ ))}
205
+ </div>
206
+ </SceneMotionLayer>
207
+ </section>
208
+ </SlideFrame>
209
+ )
210
+ },
211
+ }),
212
+ )
@@ -0,0 +1,20 @@
1
+ import type { ComponentProps } from 'react'
2
+
3
+ import { VideoComponent, type ScenePluginMetadata } from '@vibecuting/component-project-helper'
4
+
5
+ import { DefaultVideoShowcaseSlide, componentMetadata as baseComponentMetadata } from './default-video-showcase-slide'
6
+
7
+ export const componentMetadata: ScenePluginMetadata = {
8
+ ...baseComponentMetadata,
9
+ name: 'DefaultVideoShowcaseSlideLandscape',
10
+ description: 'Video showcase slide (Landscape 16:9 variant)',
11
+ sourceFile: 'src/core/scene/slide/video-showcase/default-video-showcase-slide-Landscape.tsx',
12
+ aspectRatio: '16:9',
13
+ tags: Array.from(new Set([...(baseComponentMetadata.tags ?? []), 'landscape'])),
14
+ }
15
+
16
+ export const DefaultVideoShowcaseSlideLandscape = VideoComponent(componentMetadata)(function DefaultVideoShowcaseSlideLandscape(
17
+ props: ComponentProps<typeof DefaultVideoShowcaseSlide>,
18
+ ) {
19
+ return <DefaultVideoShowcaseSlide {...props} />
20
+ })
@@ -0,0 +1,78 @@
1
+ import { DefaultVideoShowcaseSlideHorizontal } from './default-video-showcase-slide-Horizontal'
2
+ import { DefaultVideoShowcaseSlideLandscape } from './default-video-showcase-slide-Landscape'
3
+ import { DefaultVideoShowcaseMultiSlide } from './default-video-showcase-multi-slide'
4
+
5
+ const args = {
6
+ title: 'Launch trailer cut',
7
+ subtitle: 'A native video-first showcase with a poster, chapter context, runtime, and edit notes.',
8
+ chapter: 'Chapter 03',
9
+ runtimeLabel: '03:18',
10
+ posterLabel: 'Trailer poster',
11
+ posterCaption: 'Use a key frame, teaser art, or final poster still.',
12
+ notes: [
13
+ 'Fade the poster in first, then reveal the chapter label.',
14
+ 'Let the runtime badge settle before the notes appear.',
15
+ 'Use the motion pass to nudge the text blocks into place.',
16
+ ],
17
+ }
18
+
19
+ const meta = {
20
+ title: 'core/scene/slide/video-showcase/DefaultVideoShowcaseSlide/Animated',
21
+ component: DefaultVideoShowcaseSlideLandscape,
22
+ args,
23
+ }
24
+
25
+ export default meta
26
+
27
+ export const Animated = {
28
+ parameters: {
29
+ scenePreviewMode: 'animation',
30
+ scenePreviewAspectRatio: '16:9',
31
+ },
32
+ }
33
+
34
+ export const Horizontal = {
35
+ render: (storyArgs: typeof args) => <DefaultVideoShowcaseSlideHorizontal {...storyArgs} />,
36
+ parameters: {
37
+ scenePreviewMode: 'animation',
38
+ scenePreviewAspectRatio: '9:16',
39
+ },
40
+ }
41
+
42
+ export const Multi = {
43
+ render: () => (
44
+ <DefaultVideoShowcaseMultiSlide
45
+ title="Clip wall"
46
+ subtitle="Animated multi-video poster wall."
47
+ clips={[
48
+ { title: 'Opening scene', caption: 'First 8 seconds', duration: '00:08' },
49
+ { title: 'Middle beat', caption: 'Reaction shot', duration: '00:11' },
50
+ { title: 'Final cut', caption: 'Ending frame', duration: '00:14' },
51
+ { title: 'Alt take', caption: 'Alternate angle', duration: '00:09' },
52
+ ]}
53
+ />
54
+ ),
55
+ parameters: {
56
+ scenePreviewMode: 'animation',
57
+ scenePreviewAspectRatio: '16:9',
58
+ },
59
+ }
60
+
61
+ export const MultiPortrait = {
62
+ render: () => (
63
+ <DefaultVideoShowcaseMultiSlide
64
+ title="Clip wall"
65
+ subtitle="Animated multi-video poster wall."
66
+ clips={[
67
+ { title: 'Opening scene', caption: 'First 8 seconds', duration: '00:08' },
68
+ { title: 'Middle beat', caption: 'Reaction shot', duration: '00:11' },
69
+ { title: 'Final cut', caption: 'Ending frame', duration: '00:14' },
70
+ { title: 'Alt take', caption: 'Alternate angle', duration: '00:09' },
71
+ ]}
72
+ />
73
+ ),
74
+ parameters: {
75
+ scenePreviewMode: 'animation',
76
+ scenePreviewAspectRatio: '9:16',
77
+ },
78
+ }
@@ -0,0 +1,74 @@
1
+ import { DefaultVideoShowcaseSlideHorizontal } from './default-video-showcase-slide-Horizontal'
2
+ import { DefaultVideoShowcaseSlideLandscape } from './default-video-showcase-slide-Landscape'
3
+ import { DefaultVideoShowcaseMultiSlide } from './default-video-showcase-multi-slide'
4
+
5
+ const args = {
6
+ title: 'Launch trailer cut',
7
+ subtitle: 'A native video-first showcase with a poster, chapter context, runtime, and edit notes.',
8
+ chapter: 'Chapter 03',
9
+ runtimeLabel: '03:18',
10
+ posterLabel: 'Trailer poster',
11
+ posterCaption: 'Use a key frame, teaser art, or final poster still.',
12
+ notes: [
13
+ 'Open on the poster and hold the room tone for one beat.',
14
+ 'Call out the chapter change before the first transition.',
15
+ 'Keep the supporting notes concise and production-friendly.',
16
+ ],
17
+ }
18
+
19
+ const meta = {
20
+ title: 'core/scene/slide/video-showcase/DefaultVideoShowcaseSlide',
21
+ component: DefaultVideoShowcaseSlideLandscape,
22
+ args,
23
+ }
24
+
25
+ export default meta
26
+
27
+ export const Default = {
28
+ parameters: {
29
+ scenePreviewAspectRatio: '16:9',
30
+ },
31
+ }
32
+
33
+ export const Horizontal = {
34
+ render: (storyArgs: typeof args) => <DefaultVideoShowcaseSlideHorizontal {...storyArgs} />,
35
+ parameters: {
36
+ scenePreviewAspectRatio: '9:16',
37
+ },
38
+ }
39
+
40
+ export const Multi = {
41
+ render: () => (
42
+ <DefaultVideoShowcaseMultiSlide
43
+ title="Clip wall"
44
+ subtitle="A wall of multiple video posters, useful for highlights, trailers, and edit reviews."
45
+ clips={[
46
+ { title: 'Opening scene', caption: 'First 8 seconds', duration: '00:08' },
47
+ { title: 'Middle beat', caption: 'Reaction shot', duration: '00:11' },
48
+ { title: 'Final cut', caption: 'Ending frame', duration: '00:14' },
49
+ { title: 'Alt take', caption: 'Alternate angle', duration: '00:09' },
50
+ ]}
51
+ />
52
+ ),
53
+ parameters: {
54
+ scenePreviewAspectRatio: '16:9',
55
+ },
56
+ }
57
+
58
+ export const MultiPortrait = {
59
+ render: () => (
60
+ <DefaultVideoShowcaseMultiSlide
61
+ title="Clip wall"
62
+ subtitle="A wall of multiple video posters, useful for highlights, trailers, and edit reviews."
63
+ clips={[
64
+ { title: 'Opening scene', caption: 'First 8 seconds', duration: '00:08' },
65
+ { title: 'Middle beat', caption: 'Reaction shot', duration: '00:11' },
66
+ { title: 'Final cut', caption: 'Ending frame', duration: '00:14' },
67
+ { title: 'Alt take', caption: 'Alternate angle', duration: '00:09' },
68
+ ]}
69
+ />
70
+ ),
71
+ parameters: {
72
+ scenePreviewAspectRatio: '9:16',
73
+ },
74
+ }