@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,165 @@
1
+ import type { ReactNode } from 'react'
2
+
3
+ import { VideoComponent, defineComponentProjectComponentMetadata } from '@vibecuting/component-project-helper'
4
+
5
+ import { BaseRemotionScene, type BaseRemotionSceneProps, useRemotionSceneRuntime } from '../../../base'
6
+ import { useSceneMotion } from '../../../base'
7
+ import { getIntroBodyMaxWidth, getIntroLineClamp, getIntroPanelMinHeight } from '../_shared/intro-layout'
8
+
9
+ export interface DefaultFamilyIntroBumperProps extends BaseRemotionSceneProps {
10
+ title: string
11
+ subtitle?: string
12
+ kicker?: string
13
+ creditLine?: string
14
+ footer?: string
15
+ accent?: string
16
+ secondaryAccent?: string
17
+ textColor?: string
18
+ posterImageSrc?: string
19
+ posterImageAlt?: string
20
+ children?: ReactNode
21
+ }
22
+
23
+ export const componentMetadata = defineComponentProjectComponentMetadata({
24
+ name: 'DefaultFamilyIntroBumper',
25
+ description: 'Family reunion intro with photo-collage panels and reunion notes',
26
+ sourceFile: 'src/core/intro/family-intro-reunion/default-family-intro-bumper.tsx',
27
+ aspectRatio: '16:9',
28
+ sceneType: 'intro',
29
+ tags: ['intro', 'bumper', 'family', 'reunion'],
30
+ propsTypeName: 'DefaultFamilyIntroBumperProps',
31
+ })
32
+
33
+ export function DefaultFamilyIntroBumper({
34
+ id,
35
+ name,
36
+ title,
37
+ subtitle,
38
+ kicker,
39
+ creditLine,
40
+ footer,
41
+ accent,
42
+ secondaryAccent,
43
+ textColor,
44
+ posterImageSrc,
45
+ posterImageAlt,
46
+ children,
47
+ }: DefaultFamilyIntroBumperProps) {
48
+ const runtime = useRemotionSceneRuntime()
49
+ const motion = useSceneMotion()
50
+ const portrait = runtime.height > runtime.width
51
+
52
+ const text = textColor ?? '#fffaf0'
53
+ const bg = accent ?? '#78350f'
54
+ const glow = secondaryAccent ?? '#f59e0b'
55
+
56
+ return (
57
+ <BaseRemotionScene
58
+ id={id}
59
+ name={name}
60
+ style={{
61
+ background: portrait
62
+ ? `linear-gradient(180deg, #422006 0%, ${bg} 38%, #1c1917 100%)`
63
+ : `radial-gradient(circle at 18% 20%, rgba(245,158,11,0.26) 0%, ${bg} 40%, #111111 100%)`,
64
+ color: text,
65
+ display: 'grid',
66
+ placeItems: 'center',
67
+ padding: portrait ? Math.round(runtime.height * 0.06) : Math.round(runtime.height * 0.065),
68
+ }}
69
+ >
70
+ <section
71
+ style={{
72
+ position: 'relative',
73
+ zIndex: 1,
74
+ width: '100%',
75
+ height: '100%',
76
+ display: 'grid',
77
+ gridTemplateColumns: portrait ? '1fr' : 'minmax(0, 0.9fr) minmax(300px, 1.1fr)',
78
+ gap: portrait ? 18 : 26,
79
+ alignItems: 'stretch',
80
+ minWidth: 0,
81
+ minHeight: 0,
82
+ }}
83
+ >
84
+ <div style={{ display: 'grid', gap: portrait ? 14 : 16, minWidth: 0, textAlign: portrait ? 'center' : 'left', alignContent: 'center' }}>
85
+ <p style={{ margin: 0, fontSize: Math.round(runtime.height * 0.017), letterSpacing: '0.34em', textTransform: 'uppercase', opacity: 0.68 }}>
86
+ {kicker ?? 'Family Album'}
87
+ </p>
88
+ <h1
89
+ style={{
90
+ margin: 0,
91
+ fontSize: portrait ? Math.round(runtime.height * 0.08) : Math.round(runtime.height * 0.072),
92
+ lineHeight: 0.92,
93
+ letterSpacing: '-0.08em',
94
+ textTransform: 'uppercase',
95
+ transform: motion.isAnimation ? `translate3d(0, ${(1 - motion.progress) * 10}px, 0)` : 'none',
96
+ }}
97
+ >
98
+ {title}
99
+ </h1>
100
+ {subtitle ? (
101
+ <p style={{ margin: 0, maxWidth: getIntroBodyMaxWidth(runtime.width, portrait, 0.42, 1, { min: 240, max: 680 }), fontSize: Math.round(runtime.height * 0.023), lineHeight: 1.55, opacity: 0.84, ...getIntroLineClamp(portrait ? 4 : 3) }}>
102
+ {subtitle}
103
+ </p>
104
+ ) : null}
105
+ <div style={{ display: 'flex', flexWrap: 'wrap', justifyContent: portrait ? 'center' : 'flex-start', gap: 10 }}>
106
+ {creditLine ? <span style={{ fontSize: Math.round(runtime.height * 0.015), letterSpacing: '0.22em', textTransform: 'uppercase', opacity: 0.82 }}>{creditLine}</span> : null}
107
+ {footer ? <span style={{ fontSize: Math.round(runtime.height * 0.015), letterSpacing: '0.2em', textTransform: 'uppercase', opacity: 0.56 }}>{footer}</span> : null}
108
+ </div>
109
+ </div>
110
+
111
+ <div style={{ display: 'grid', gap: 12, minWidth: 0, alignContent: 'center' }}>
112
+ <div style={{ border: '1px solid rgba(255,250,240,0.16)', background: 'linear-gradient(180deg, rgba(255,255,255,0.06), rgba(120,53,15,0.16))', padding: portrait ? 18 : 22, display: 'grid', gap: 12, overflow: 'hidden', minHeight: getIntroPanelMinHeight(runtime.height, portrait, 0.3, 0.24, { min: 220, max: 360 }) }}>
113
+ <div style={{ display: 'grid', gridTemplateColumns: portrait ? '1fr' : 'minmax(0, 0.98fr) minmax(220px, 0.82fr)', gap: 10, minWidth: 0 }}>
114
+ <div style={{ display: 'grid', gap: 10 }}>
115
+ <div style={{ display: 'grid', gridTemplateColumns: portrait ? '1fr' : 'repeat(2, minmax(0, 1fr))', gap: 10 }}>
116
+ {['Grandma', 'Parents', 'Children', 'Guests'].map((label, index) => (
117
+ <div
118
+ key={label}
119
+ style={{
120
+ minHeight: portrait ? 60 : 96,
121
+ border: '1px solid rgba(255,250,240,0.14)',
122
+ background: index % 2 === 0 ? 'rgba(0,0,0,0.16)' : 'linear-gradient(180deg, rgba(245,158,11,0.18), rgba(0,0,0,0.08))',
123
+ display: 'grid',
124
+ placeItems: 'center',
125
+ textAlign: 'center',
126
+ padding: 10,
127
+ }}
128
+ >
129
+ <div style={{ fontSize: Math.round(runtime.height * 0.016), letterSpacing: '0.24em', textTransform: 'uppercase', opacity: 0.74 }}>
130
+ {label}
131
+ </div>
132
+ </div>
133
+ ))}
134
+ </div>
135
+ <div style={{ border: '1px solid rgba(255,250,240,0.12)', background: 'rgba(0,0,0,0.16)', padding: 14, display: 'grid', gap: 8 }}>
136
+ <span style={{ fontSize: Math.round(runtime.height * 0.014), letterSpacing: '0.22em', textTransform: 'uppercase', opacity: 0.56 }}>Album Notes</span>
137
+ <span style={{ fontSize: Math.round(runtime.height * 0.02) }}>A collage opener that feels like a table of printed photos.</span>
138
+ </div>
139
+ </div>
140
+ {posterImageSrc ? (
141
+ <div style={{ minHeight: portrait ? 160 : 280, border: '1px solid rgba(255,250,240,0.14)', background: 'rgba(0,0,0,0.16)', overflow: 'hidden' }}>
142
+ <img src={posterImageSrc} alt={posterImageAlt ?? title} style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
143
+ </div>
144
+ ) : null}
145
+ </div>
146
+ <div style={{ height: 1, background: `linear-gradient(90deg, transparent, ${glow}, transparent)` }} />
147
+ <div style={{ display: 'grid', gap: 8, fontSize: Math.round(runtime.height * 0.02) }}>
148
+ <div style={{ display: 'flex', justifyContent: 'space-between', gap: 12 }}>
149
+ <span>Location</span>
150
+ <span>Homecoming dinner</span>
151
+ </div>
152
+ <div style={{ display: 'flex', justifyContent: 'space-between', gap: 12 }}>
153
+ <span>Album</span>
154
+ <span>Reunion season</span>
155
+ </div>
156
+ </div>
157
+ </div>
158
+ {children ? <div>{children}</div> : null}
159
+ </div>
160
+ </section>
161
+ </BaseRemotionScene>
162
+ )
163
+ }
164
+
165
+ VideoComponent(componentMetadata)(DefaultFamilyIntroBumper)
@@ -0,0 +1,10 @@
1
+ export { DefaultFamilyIntroBumper } from './default-family-intro-bumper'
2
+ export { componentMetadata } from './default-family-intro-bumper'
3
+ export {
4
+ DefaultFamilyIntroBumperLandscape,
5
+ componentMetadata as DefaultFamilyIntroBumperLandscapeMetadata,
6
+ } from './default-family-intro-bumper-Landscape'
7
+ export {
8
+ DefaultFamilyIntroBumperHorizontal,
9
+ componentMetadata as DefaultFamilyIntroBumperHorizontalMetadata,
10
+ } from './default-family-intro-bumper-Horizontal'
@@ -0,0 +1 @@
1
+ export { DefaultFestivalIntroBumperSpotlight as DefaultFestivalIntroBumperSpotlightHorizontal, componentMetadata } from './default-festival-intro-bumper'
@@ -0,0 +1 @@
1
+ export { DefaultFestivalIntroBumperSpotlight as DefaultFestivalIntroBumperSpotlightLandscape, componentMetadata } from './default-festival-intro-bumper'
@@ -0,0 +1,30 @@
1
+ import { DefaultFestivalIntroBumperSpotlightHorizontal } from './default-festival-intro-bumper-Horizontal'
2
+ import { DefaultFestivalIntroBumperSpotlightLandscape } from './default-festival-intro-bumper-Landscape'
3
+
4
+ const args = {
5
+ kicker: 'Festival Premiere',
6
+ title: 'Standing Ovation',
7
+ subtitle: 'A celebratory intro bumper with a brighter, award-season visual language.',
8
+ creditLine: 'A Vibecuting Original',
9
+ footer: 'Opening Sequence',
10
+ accent: '#7c3aed',
11
+ secondaryAccent: '#f59e0b',
12
+ }
13
+
14
+ const meta = {
15
+ title: 'core/intro/festival-intro-spotlight/DefaultFestivalIntroBumperSpotlight',
16
+ component: DefaultFestivalIntroBumperSpotlightLandscape,
17
+ args,
18
+ }
19
+
20
+ export default meta
21
+ export const Landscape = { parameters: { scenePreviewAspectRatio: '16:9' } }
22
+ export const LandscapeAnimated = { parameters: { scenePreviewAspectRatio: '16:9', scenePreviewMode: 'animation' } }
23
+ export const Horizontal = {
24
+ render: (storyArgs: typeof args) => <DefaultFestivalIntroBumperSpotlightHorizontal {...storyArgs} />,
25
+ parameters: { scenePreviewAspectRatio: '9:16' },
26
+ }
27
+ export const HorizontalAnimated = {
28
+ render: (storyArgs: typeof args) => <DefaultFestivalIntroBumperSpotlightHorizontal {...storyArgs} />,
29
+ parameters: { scenePreviewAspectRatio: '9:16', scenePreviewMode: 'animation' },
30
+ }
@@ -0,0 +1,105 @@
1
+ import type { ReactNode } from 'react'
2
+
3
+ import { VideoComponent, defineComponentProjectComponentMetadata } from '@vibecuting/component-project-helper'
4
+
5
+ import { BaseRemotionScene, type BaseRemotionSceneProps, useRemotionSceneRuntime } from '../../../base'
6
+ import { useSceneMotion } from '../../../base'
7
+ import { getIntroBodyMaxWidth, getIntroLineClamp, getIntroPanelMinHeight, getIntroPanelPadding } from '../_shared/intro-layout'
8
+
9
+ export interface DefaultFestivalIntroBumperSpotlightProps extends BaseRemotionSceneProps {
10
+ title: string
11
+ subtitle?: string
12
+ kicker?: string
13
+ creditLine?: string
14
+ footer?: string
15
+ accent?: string
16
+ secondaryAccent?: string
17
+ textColor?: string
18
+ children?: ReactNode
19
+ }
20
+
21
+ export const componentMetadata = defineComponentProjectComponentMetadata({
22
+ name: 'DefaultFestivalIntroBumperSpotlight',
23
+ description: 'Festival premiere-style intro bumper with a poster wall and award-night framing',
24
+ sourceFile: 'src/core/intro/festival-intro-spotlight/default-festival-intro-bumper.tsx',
25
+ aspectRatio: '16:9',
26
+ sceneType: 'intro',
27
+ tags: ['intro', 'bumper', 'festival', 'spotlight', 'premiere'],
28
+ propsTypeName: 'DefaultFestivalIntroBumperSpotlightProps',
29
+ })
30
+
31
+ export function DefaultFestivalIntroBumperSpotlight({
32
+ id,
33
+ name,
34
+ title,
35
+ subtitle,
36
+ kicker,
37
+ creditLine,
38
+ footer,
39
+ accent,
40
+ secondaryAccent,
41
+ textColor,
42
+ children,
43
+ }: DefaultFestivalIntroBumperSpotlightProps) {
44
+ const runtime = useRemotionSceneRuntime()
45
+ const motion = useSceneMotion()
46
+ const portrait = runtime.height > runtime.width
47
+
48
+ return (
49
+ <BaseRemotionScene
50
+ id={id}
51
+ name={name}
52
+ style={{
53
+ background: portrait
54
+ ? `linear-gradient(180deg, ${accent ?? '#7c3aed'} 0%, #1e1b4b 40%, #020617 100%)`
55
+ : `radial-gradient(circle at 50% 22%, ${secondaryAccent ?? '#f59e0b'} 0%, ${accent ?? '#7c3aed'} 44%, #020617 100%)`,
56
+ color: textColor ?? '#f5f3ff',
57
+ display: 'grid',
58
+ placeItems: 'center',
59
+ padding: Math.round(runtime.height * 0.07),
60
+ }}
61
+ >
62
+ <section
63
+ style={{
64
+ width: '100%',
65
+ height: '100%',
66
+ display: 'grid',
67
+ gridTemplateColumns: portrait ? '1fr' : 'minmax(0, 1.02fr) minmax(260px, 0.98fr)',
68
+ gap: portrait ? 18 : 26,
69
+ alignItems: 'center',
70
+ minWidth: 0,
71
+ minHeight: 0,
72
+ }}
73
+ >
74
+ <div style={{ display: 'grid', gap: 12, textAlign: portrait ? 'center' : 'left', minWidth: 0 }}>
75
+ <p style={{ margin: 0, fontSize: Math.round(runtime.height * 0.017), letterSpacing: '0.34em', textTransform: 'uppercase', opacity: 0.68 }}>
76
+ {kicker ?? 'Festival Premiere'}
77
+ </p>
78
+ <h1 style={{ margin: 0, fontSize: portrait ? Math.round(runtime.height * 0.08) : Math.round(runtime.height * 0.072), lineHeight: 0.9, letterSpacing: '-0.08em', textTransform: 'uppercase', transform: motion.isAnimation ? `translate3d(0, ${(1 - motion.progress) * 10}px, 0)` : 'none' }}>
79
+ {title}
80
+ </h1>
81
+ {subtitle ? <p style={{ margin: 0, maxWidth: getIntroBodyMaxWidth(runtime.width, portrait, 0.42, 1, { min: 240, max: 680 }), fontSize: Math.round(runtime.height * 0.024), lineHeight: 1.56, opacity: 0.82, ...getIntroLineClamp(portrait ? 4 : 3) }}>{subtitle}</p> : null}
82
+ <div style={{ display: 'flex', flexWrap: 'wrap', justifyContent: portrait ? 'center' : 'flex-start', gap: 10 }}>
83
+ {creditLine ? <span style={{ fontSize: Math.round(runtime.height * 0.015), letterSpacing: '0.2em', textTransform: 'uppercase', opacity: 0.72 }}>{creditLine}</span> : null}
84
+ {footer ? <span style={{ fontSize: Math.round(runtime.height * 0.015), letterSpacing: '0.2em', textTransform: 'uppercase', opacity: 0.52 }}>{footer}</span> : null}
85
+ </div>
86
+ </div>
87
+
88
+ <div style={{ display: 'grid', alignContent: 'center', justifyItems: portrait ? 'center' : 'end', minWidth: 0 }}>
89
+ <div style={{ width: '100%', minWidth: 0, aspectRatio: '4 / 5', border: '1px solid rgba(245,243,255,0.12)', background: 'linear-gradient(160deg, rgba(245,158,11,0.22) 0%, rgba(124,58,237,0.18) 38%, rgba(2,6,23,0.96) 100%)', position: 'relative', overflow: 'hidden', padding: getIntroPanelPadding(runtime.height, portrait, 0.008, 0.007, { min: 12, max: 18 }), minHeight: getIntroPanelMinHeight(runtime.height, portrait, 0.3, 0.24, { min: 180, max: 320 }) }}>
90
+ <div style={{ position: 'absolute', inset: 16, border: '1px solid rgba(245,243,255,0.08)' }} />
91
+ <div style={{ position: 'absolute', inset: '16% 12%', border: '1px solid rgba(245,158,11,0.14)', borderRadius: 9999, transform: motion.isAnimation ? `scale(${0.97 + motion.progress * 0.03})` : 'none' }} />
92
+ <div style={{ position: 'absolute', left: 18, right: 18, top: 18, height: 2, background: 'linear-gradient(90deg, transparent 0%, rgba(245,158,11,0.95) 50%, transparent 100%)' }} />
93
+ <div style={{ position: 'absolute', left: 18, right: 18, bottom: 18, display: 'grid', gap: 8 }}>
94
+ <div style={{ fontSize: Math.round(runtime.height * 0.017), letterSpacing: '0.24em', textTransform: 'uppercase', opacity: 0.58 }}>Premiere Night</div>
95
+ <div style={{ fontSize: Math.round(runtime.height * 0.029), fontWeight: 800, letterSpacing: '-0.06em' }}>Spotlight on the story</div>
96
+ </div>
97
+ </div>
98
+ </div>
99
+ </section>
100
+ {children ? <div style={{ position: 'absolute', inset: 'auto 0 8%', display: 'grid', placeItems: 'center' }}>{children}</div> : null}
101
+ </BaseRemotionScene>
102
+ )
103
+ }
104
+
105
+ VideoComponent(componentMetadata)(DefaultFestivalIntroBumperSpotlight)
@@ -0,0 +1,10 @@
1
+ export { DefaultFestivalIntroBumperSpotlight } from './default-festival-intro-bumper'
2
+ export { componentMetadata } from './default-festival-intro-bumper'
3
+ export {
4
+ DefaultFestivalIntroBumperSpotlightLandscape,
5
+ componentMetadata as DefaultFestivalIntroBumperSpotlightLandscapeMetadata,
6
+ } from './default-festival-intro-bumper-Landscape'
7
+ export {
8
+ DefaultFestivalIntroBumperSpotlightHorizontal,
9
+ componentMetadata as DefaultFestivalIntroBumperSpotlightHorizontalMetadata,
10
+ } from './default-festival-intro-bumper-Horizontal'
@@ -0,0 +1,45 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import {
4
+ DefaultCinematicIntroBumper,
5
+ DefaultFestivalIntroBumper,
6
+ DefaultFestivalIntroBumperSpotlight,
7
+ DefaultIntroBumper,
8
+ DefaultNoirIntroBumper,
9
+ DefaultNoirIntroBumperDeluxe,
10
+ DefaultNoirIntroBumperCity,
11
+ DefaultCyberpunkIntroBumperNeon,
12
+ DefaultCyberpunkIntroBumperHolo,
13
+ DefaultDocumentaryIntroBumper,
14
+ DefaultFamilyIntroBumper,
15
+ DefaultSciFiIntroBumper,
16
+ DefaultTrailerIntroBumper,
17
+ DefaultTrailerIntroBumperPremiere,
18
+ DefaultWesternIntroBumper,
19
+ DefaultWesternIntroBumperGangster,
20
+ DefaultThrillerIntroBumper,
21
+ DefaultTravelIntroBumper,
22
+ } from './index'
23
+
24
+ describe('core intro exports', () => {
25
+ it('exports all intro bumper styles', () => {
26
+ expect(DefaultIntroBumper).toBeTypeOf('function')
27
+ expect(DefaultCinematicIntroBumper).toBeTypeOf('function')
28
+ expect(DefaultNoirIntroBumper).toBeTypeOf('function')
29
+ expect(DefaultTrailerIntroBumper).toBeTypeOf('function')
30
+ expect(DefaultFestivalIntroBumper).toBeTypeOf('function')
31
+ expect(DefaultWesternIntroBumper).toBeTypeOf('function')
32
+ expect(DefaultWesternIntroBumperGangster).toBeTypeOf('function')
33
+ expect(DefaultSciFiIntroBumper).toBeTypeOf('function')
34
+ expect(DefaultNoirIntroBumperDeluxe).toBeTypeOf('function')
35
+ expect(DefaultTrailerIntroBumperPremiere).toBeTypeOf('function')
36
+ expect(DefaultFestivalIntroBumperSpotlight).toBeTypeOf('function')
37
+ expect(DefaultNoirIntroBumperCity).toBeTypeOf('function')
38
+ expect(DefaultCyberpunkIntroBumperNeon).toBeTypeOf('function')
39
+ expect(DefaultCyberpunkIntroBumperHolo).toBeTypeOf('function')
40
+ expect(DefaultDocumentaryIntroBumper).toBeTypeOf('function')
41
+ expect(DefaultFamilyIntroBumper).toBeTypeOf('function')
42
+ expect(DefaultThrillerIntroBumper).toBeTypeOf('function')
43
+ expect(DefaultTravelIntroBumper).toBeTypeOf('function')
44
+ })
45
+ })
@@ -1 +1,18 @@
1
1
  export { DefaultIntroBumper } from './default-intro-bumper'
2
+ export { DefaultCinematicIntroBumper } from './default-cinematic-intro-bumper'
3
+ export { DefaultNoirIntroBumper } from './default-noir-intro-bumper'
4
+ export { DefaultTrailerIntroBumper } from './default-trailer-intro-bumper'
5
+ export { DefaultFestivalIntroBumper } from './default-festival-intro-bumper'
6
+ export { DefaultWesternIntroBumper } from './western-intro'
7
+ export { DefaultSciFiIntroBumper } from './sci-fi-intro'
8
+ export { DefaultNoirIntroBumperDeluxe } from './noir-intro-deluxe'
9
+ export { DefaultTrailerIntroBumperPremiere } from './trailer-intro-premiere'
10
+ export { DefaultFestivalIntroBumperSpotlight } from './festival-intro-spotlight'
11
+ export { DefaultNoirIntroBumperCity } from './noir-intro-city'
12
+ export { DefaultCyberpunkIntroBumperNeon } from './cyberpunk-intro-neon'
13
+ export { DefaultWesternIntroBumperGangster } from './western-intro-gangster'
14
+ export { DefaultCyberpunkIntroBumperHolo } from './cyberpunk-intro-holo'
15
+ export { DefaultDocumentaryIntroBumper } from './documentary-intro-observation'
16
+ export { DefaultThrillerIntroBumper } from './thriller-intro-suspense'
17
+ export { DefaultFamilyIntroBumper } from './family-intro-reunion'
18
+ export { DefaultTravelIntroBumper } from './travel-intro-journey'
@@ -0,0 +1,24 @@
1
+ import type { ComponentProps } from 'react'
2
+
3
+ import { VideoComponent, type ScenePluginMetadata } from '@vibecuting/component-project-helper'
4
+
5
+ import { DefaultNoirIntroBumperCity, componentMetadata as baseComponentMetadata } from './default-noir-intro-bumper'
6
+
7
+ export const componentMetadata: ScenePluginMetadata = {
8
+ ...baseComponentMetadata,
9
+ resourceKind: 'scene',
10
+ pluginKey: 'core.intro.noir-city',
11
+ sceneFamily: 'custom',
12
+ rootLayout: 'absolute-fill',
13
+ name: 'DefaultNoirIntroBumperCityHorizontal',
14
+ description: 'Noir city intro bumper (Portrait 9:16 variant)',
15
+ sourceFile: 'src/core/intro/noir-intro-city/default-noir-intro-bumper-Horizontal.tsx',
16
+ aspectRatio: '9:16',
17
+ tags: Array.from(new Set([...(baseComponentMetadata.tags ?? []), 'horizontal'])),
18
+ }
19
+
20
+ export const DefaultNoirIntroBumperCityHorizontal = VideoComponent(componentMetadata)(function DefaultNoirIntroBumperCityHorizontal(
21
+ props: ComponentProps<typeof DefaultNoirIntroBumperCity>,
22
+ ) {
23
+ return <DefaultNoirIntroBumperCity {...props} />
24
+ })
@@ -0,0 +1,24 @@
1
+ import type { ComponentProps } from 'react'
2
+
3
+ import { VideoComponent, type ScenePluginMetadata } from '@vibecuting/component-project-helper'
4
+
5
+ import { DefaultNoirIntroBumperCity, componentMetadata as baseComponentMetadata } from './default-noir-intro-bumper'
6
+
7
+ export const componentMetadata: ScenePluginMetadata = {
8
+ ...baseComponentMetadata,
9
+ resourceKind: 'scene',
10
+ pluginKey: 'core.intro.noir-city',
11
+ sceneFamily: 'custom',
12
+ rootLayout: 'absolute-fill',
13
+ name: 'DefaultNoirIntroBumperCityLandscape',
14
+ description: 'Noir city intro bumper (Landscape 16:9 variant)',
15
+ sourceFile: 'src/core/intro/noir-intro-city/default-noir-intro-bumper-Landscape.tsx',
16
+ aspectRatio: '16:9',
17
+ tags: Array.from(new Set([...(baseComponentMetadata.tags ?? []), 'landscape'])),
18
+ }
19
+
20
+ export const DefaultNoirIntroBumperCityLandscape = VideoComponent(componentMetadata)(function DefaultNoirIntroBumperCityLandscape(
21
+ props: ComponentProps<typeof DefaultNoirIntroBumperCity>,
22
+ ) {
23
+ return <DefaultNoirIntroBumperCity {...props} />
24
+ })
@@ -0,0 +1,31 @@
1
+ import { DefaultNoirIntroBumperCityHorizontal } from './default-noir-intro-bumper-Horizontal'
2
+ import { DefaultNoirIntroBumperCityLandscape } from './default-noir-intro-bumper-Landscape'
3
+
4
+ const args = {
5
+ kicker: 'Noir City',
6
+ title: 'Midnight Streets',
7
+ subtitle: 'A sharper noir opener with more urban tension and detective energy.',
8
+ creditLine: 'A Vibecuting Original',
9
+ footer: 'Opening Sequence',
10
+ accent: '#050505',
11
+ secondaryAccent: '#6b7280',
12
+ }
13
+
14
+ const meta = {
15
+ title: 'core/intro/noir-intro-city/DefaultNoirIntroBumperCity',
16
+ component: DefaultNoirIntroBumperCityLandscape,
17
+ args,
18
+ }
19
+
20
+ export default meta
21
+
22
+ export const Landscape = { parameters: { scenePreviewAspectRatio: '16:9' } }
23
+ export const LandscapeAnimated = { parameters: { scenePreviewAspectRatio: '16:9', scenePreviewMode: 'animation' } }
24
+ export const Horizontal = {
25
+ render: (storyArgs: typeof args) => <DefaultNoirIntroBumperCityHorizontal {...storyArgs} />,
26
+ parameters: { scenePreviewAspectRatio: '9:16' },
27
+ }
28
+ export const HorizontalAnimated = {
29
+ render: (storyArgs: typeof args) => <DefaultNoirIntroBumperCityHorizontal {...storyArgs} />,
30
+ parameters: { scenePreviewAspectRatio: '9:16', scenePreviewMode: 'animation' },
31
+ }
@@ -0,0 +1,96 @@
1
+ import type { ReactNode } from 'react'
2
+
3
+ import { VideoComponent, defineComponentProjectComponentMetadata } from '@vibecuting/component-project-helper'
4
+
5
+ import { BaseRemotionScene, type BaseRemotionSceneProps, useRemotionSceneRuntime } from '../../../base'
6
+ import { useSceneMotion } from '../../../base'
7
+ import { getIntroBodyMaxWidth, getIntroLineClamp, getIntroPanelMinHeight, getIntroPanelPadding } from '../_shared/intro-layout'
8
+
9
+ export interface DefaultNoirIntroBumperCityProps extends BaseRemotionSceneProps {
10
+ title: string
11
+ subtitle?: string
12
+ kicker?: string
13
+ creditLine?: string
14
+ footer?: string
15
+ accent?: string
16
+ secondaryAccent?: string
17
+ textColor?: string
18
+ children?: ReactNode
19
+ }
20
+
21
+ export const componentMetadata = defineComponentProjectComponentMetadata({
22
+ name: 'DefaultNoirIntroBumperCity',
23
+ description: 'Noir city intro bumper with smoky skyline framing and a detective dossier layout',
24
+ sourceFile: 'src/core/intro/noir-intro-city/default-noir-intro-bumper.tsx',
25
+ aspectRatio: '16:9',
26
+ sceneType: 'intro',
27
+ tags: ['intro', 'bumper', 'noir', 'city', 'detective'],
28
+ propsTypeName: 'DefaultNoirIntroBumperCityProps',
29
+ })
30
+
31
+ export function DefaultNoirIntroBumperCity({
32
+ id,
33
+ name,
34
+ title,
35
+ subtitle,
36
+ kicker,
37
+ creditLine,
38
+ footer,
39
+ accent,
40
+ secondaryAccent,
41
+ textColor,
42
+ children,
43
+ }: DefaultNoirIntroBumperCityProps) {
44
+ const runtime = useRemotionSceneRuntime()
45
+ const motion = useSceneMotion()
46
+ const portrait = runtime.height > runtime.width
47
+
48
+ return (
49
+ <BaseRemotionScene
50
+ id={id}
51
+ name={name}
52
+ style={{
53
+ background: portrait
54
+ ? `linear-gradient(180deg, #050505 0%, ${accent ?? '#101010'} 40%, #000000 100%)`
55
+ : `radial-gradient(circle at 50% 18%, ${secondaryAccent ?? 'rgba(255,255,255,0.08)'} 0%, ${accent ?? '#050505'} 44%, #000 100%)`,
56
+ color: textColor ?? '#f5f5f5',
57
+ display: 'grid',
58
+ placeItems: 'center',
59
+ padding: Math.round(runtime.height * 0.07),
60
+ fontFamily: `Georgia, 'Times New Roman', serif`,
61
+ }}
62
+ >
63
+ <div aria-hidden="true" style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(255,255,255,0.03) 0%, rgba(0,0,0,0.12) 20%, rgba(0,0,0,0.72) 100%)', pointerEvents: 'none' }} />
64
+ <section style={{ position: 'relative', zIndex: 1, width: '100%', height: '100%', display: 'grid', gridTemplateColumns: portrait ? '1fr' : 'minmax(0, 1.04fr) minmax(260px, 0.96fr)', gap: portrait ? 18 : 24, alignItems: 'center', minWidth: 0, minHeight: 0, overflow: 'hidden' }}>
65
+ <div style={{ display: 'grid', gap: 12, textAlign: portrait ? 'center' : 'left', minWidth: 0 }}>
66
+ <p style={{ margin: 0, fontSize: Math.round(runtime.height * 0.017), letterSpacing: '0.4em', textTransform: 'uppercase', opacity: 0.62 }}>
67
+ {kicker ?? 'City Lights'}
68
+ </p>
69
+ <h1 style={{ margin: 0, fontSize: portrait ? Math.round(runtime.height * 0.078) : Math.round(runtime.height * 0.072), lineHeight: 0.9, letterSpacing: '-0.08em', textTransform: 'uppercase', transform: motion.isAnimation ? `translate3d(0, ${(1 - motion.progress) * 8}px, 0)` : 'none' }}>
70
+ {title}
71
+ </h1>
72
+ {subtitle ? <p style={{ margin: 0, maxWidth: getIntroBodyMaxWidth(runtime.width, portrait, 0.44, 1, { min: 240, max: 700 }), fontSize: Math.round(runtime.height * 0.024), lineHeight: 1.6, opacity: 0.8, ...getIntroLineClamp(portrait ? 4 : 3) }}>{subtitle}</p> : null}
73
+ <div style={{ display: 'flex', flexWrap: 'wrap', justifyContent: portrait ? 'center' : 'flex-start', gap: 10 }}>
74
+ {creditLine ? <span style={{ fontSize: Math.round(runtime.height * 0.015), letterSpacing: '0.22em', textTransform: 'uppercase', opacity: 0.72 }}>{creditLine}</span> : null}
75
+ {footer ? <span style={{ fontSize: Math.round(runtime.height * 0.015), letterSpacing: '0.2em', textTransform: 'uppercase', opacity: 0.52 }}>{footer}</span> : null}
76
+ </div>
77
+ </div>
78
+
79
+ <div style={{ display: 'grid', alignContent: 'center', justifyItems: portrait ? 'center' : 'end', minWidth: 0 }}>
80
+ <div style={{ width: '100%', minWidth: 0, aspectRatio: '4 / 5', border: '1px solid rgba(255,255,255,0.12)', background: 'linear-gradient(180deg, rgba(255,255,255,0.04) 0%, rgba(0,0,0,0.18) 42%, rgba(0,0,0,0.86) 100%)', position: 'relative', overflow: 'hidden', padding: getIntroPanelPadding(runtime.height, portrait, 0.008, 0.007, { min: 12, max: 18 }), minHeight: getIntroPanelMinHeight(runtime.height, portrait, 0.28, 0.22, { min: 160, max: 300 }) }}>
81
+ <div style={{ position: 'absolute', inset: 18, border: '1px solid rgba(255,255,255,0.08)' }} />
82
+ <div style={{ position: 'absolute', left: 20, top: 20, width: '24%', height: '2px', background: 'linear-gradient(90deg, rgba(255,255,255,0.75), transparent)' }} />
83
+ <div style={{ position: 'absolute', right: 20, bottom: 20, width: '28%', height: '2px', background: 'linear-gradient(90deg, transparent, rgba(255,255,255,0.7))' }} />
84
+ <div style={{ position: 'absolute', left: 18, right: 18, bottom: 18, display: 'grid', gap: 8 }}>
85
+ <div style={{ fontSize: Math.round(runtime.height * 0.017), letterSpacing: '0.24em', textTransform: 'uppercase', opacity: 0.58 }}>Smoke and Rain</div>
86
+ <div style={{ fontSize: Math.round(runtime.height * 0.029), fontWeight: 800, letterSpacing: '-0.06em' }}>Another case begins</div>
87
+ </div>
88
+ </div>
89
+ </div>
90
+ </section>
91
+ {children ? <div style={{ position: 'absolute', inset: 'auto 0 8%', display: 'grid', placeItems: 'center' }}>{children}</div> : null}
92
+ </BaseRemotionScene>
93
+ )
94
+ }
95
+
96
+ VideoComponent(componentMetadata)(DefaultNoirIntroBumperCity)
@@ -0,0 +1,10 @@
1
+ export { DefaultNoirIntroBumperCity } from './default-noir-intro-bumper'
2
+ export { componentMetadata } from './default-noir-intro-bumper'
3
+ export {
4
+ DefaultNoirIntroBumperCityLandscape,
5
+ componentMetadata as DefaultNoirIntroBumperCityLandscapeMetadata,
6
+ } from './default-noir-intro-bumper-Landscape'
7
+ export {
8
+ DefaultNoirIntroBumperCityHorizontal,
9
+ componentMetadata as DefaultNoirIntroBumperCityHorizontalMetadata,
10
+ } from './default-noir-intro-bumper-Horizontal'
@@ -0,0 +1 @@
1
+ export { DefaultNoirIntroBumperDeluxe as DefaultNoirIntroBumperDeluxeHorizontal, componentMetadata } from './default-noir-intro-bumper'
@@ -0,0 +1 @@
1
+ export { DefaultNoirIntroBumperDeluxe as DefaultNoirIntroBumperDeluxeLandscape, componentMetadata } from './default-noir-intro-bumper'
@@ -0,0 +1,31 @@
1
+ import { DefaultNoirIntroBumperDeluxeHorizontal } from './default-noir-intro-bumper-Horizontal'
2
+ import { DefaultNoirIntroBumperDeluxeLandscape } from './default-noir-intro-bumper-Landscape'
3
+
4
+ const args = {
5
+ kicker: 'Noir Deluxe',
6
+ title: 'Midnight Evidence',
7
+ subtitle: 'A smoky opening card for detective stories, hard-boiled edits, and moody reveals.',
8
+ creditLine: 'A Vibecuting Original',
9
+ footer: 'Opening Sequence',
10
+ accent: '#050505',
11
+ secondaryAccent: '#7c7c7c',
12
+ }
13
+
14
+ const meta = {
15
+ title: 'core/intro/noir-intro-deluxe/DefaultNoirIntroBumperDeluxe',
16
+ component: DefaultNoirIntroBumperDeluxeLandscape,
17
+ args,
18
+ }
19
+
20
+ export default meta
21
+
22
+ export const Landscape = { parameters: { scenePreviewAspectRatio: '16:9' } }
23
+ export const LandscapeAnimated = { parameters: { scenePreviewAspectRatio: '16:9', scenePreviewMode: 'animation' } }
24
+ export const Horizontal = {
25
+ render: (storyArgs: typeof args) => <DefaultNoirIntroBumperDeluxeHorizontal {...storyArgs} />,
26
+ parameters: { scenePreviewAspectRatio: '9:16' },
27
+ }
28
+ export const HorizontalAnimated = {
29
+ render: (storyArgs: typeof args) => <DefaultNoirIntroBumperDeluxeHorizontal {...storyArgs} />,
30
+ parameters: { scenePreviewAspectRatio: '9:16', scenePreviewMode: 'animation' },
31
+ }