reelkit-cli 0.8.0 → 0.10.2

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 (122) hide show
  1. package/README.md +13 -1
  2. package/package.json +49 -10
  3. package/skill/.claude-plugin/plugin.json +7 -0
  4. package/skill/SKILL.md +44 -19
  5. package/skill/THIRD_PARTY.md +37 -5
  6. package/skill/commands/launch-film.md +1 -1
  7. package/skill/hooks/hooks.json +1 -0
  8. package/skill/hooks/player.ts +278 -0
  9. package/skill/hooks/project.ts +227 -0
  10. package/skill/hooks/register.tsx +533 -0
  11. package/skill/hooks/timeline.ts +218 -0
  12. package/skill/reference/art-styles.md +70 -0
  13. package/skill/reference/backgrounds.md +1 -1
  14. package/skill/reference/brand-motion.md +62 -0
  15. package/skill/reference/clips.md +3 -3
  16. package/skill/reference/component-authoring.md +3 -1
  17. package/skill/reference/continuity.md +5 -5
  18. package/skill/reference/delivery-review.md +40 -0
  19. package/skill/reference/hebrew-rtl.md +3 -4
  20. package/skill/reference/higgsfield-production.md +70 -0
  21. package/skill/reference/{remotion-composition.md → hyperframes-composition.md} +14 -8
  22. package/skill/reference/kit.md +7 -3
  23. package/skill/reference/launch-film.md +13 -9
  24. package/skill/reference/motion-design.md +26 -22
  25. package/skill/reference/sound-design.md +34 -12
  26. package/skill/reference/studio-editing.md +55 -0
  27. package/skill/reference/studio-pane.md +31 -0
  28. package/skill/reference/style-components.md +40 -0
  29. package/skill/reference/style-recipes.md +86 -0
  30. package/skill/reference/styles.md +17 -10
  31. package/skill/reference/three-d.md +8 -7
  32. package/skill/reference/voice-sync.md +1 -1
  33. package/skill/tests/studio.test.ts +111 -0
  34. package/skill/types/index.d.ts +65 -0
  35. package/src/commands/assets.ts +5 -1
  36. package/src/contract/index.ts +1 -1
  37. package/src/hyperframes/Root.tsx +1 -0
  38. package/src/hyperframes/fonts.ts +54 -0
  39. package/src/hyperframes/frame.tsx +46 -0
  40. package/src/hyperframes/host.tsx +38 -0
  41. package/src/{remotion → hyperframes}/kit/Assemble3D.tsx +1 -1
  42. package/src/hyperframes/kit/BrandTransform3D.tsx +12 -0
  43. package/src/{remotion → hyperframes}/kit/BrowserFrame.tsx +1 -1
  44. package/src/{remotion → hyperframes}/kit/Camera.tsx +1 -1
  45. package/src/{remotion → hyperframes}/kit/Captions.tsx +1 -1
  46. package/src/{remotion → hyperframes}/kit/Card3D.tsx +2 -2
  47. package/src/{remotion → hyperframes}/kit/Carry.tsx +1 -1
  48. package/src/{remotion → hyperframes}/kit/ChapterFrame.tsx +1 -1
  49. package/src/{remotion → hyperframes}/kit/ClipLayer.tsx +1 -1
  50. package/src/{remotion → hyperframes}/kit/Counter.tsx +1 -1
  51. package/src/{remotion → hyperframes}/kit/CounterRoll.tsx +1 -1
  52. package/src/{remotion → hyperframes}/kit/Entrance.tsx +1 -1
  53. package/src/{remotion → hyperframes}/kit/FootageLayer.tsx +1 -1
  54. package/src/{remotion → hyperframes}/kit/GlassPanel.tsx +1 -1
  55. package/src/{remotion → hyperframes}/kit/Grounds.tsx +1 -1
  56. package/src/{remotion → hyperframes}/kit/Headline.tsx +1 -1
  57. package/src/{remotion → hyperframes}/kit/Hero3D.tsx +1 -1
  58. package/src/{remotion → hyperframes}/kit/HudOverlay.tsx +1 -1
  59. package/src/{remotion → hyperframes}/kit/ImageLayers.tsx +1 -1
  60. package/src/{remotion → hyperframes}/kit/KenBurnsImage.tsx +1 -1
  61. package/src/{remotion → hyperframes}/kit/KeyedClip.tsx +1 -1
  62. package/src/{remotion → hyperframes}/kit/Layers.tsx +1 -1
  63. package/src/{remotion → hyperframes}/kit/LowerThird.tsx +1 -1
  64. package/src/{remotion → hyperframes}/kit/Music.tsx +1 -1
  65. package/src/{remotion → hyperframes}/kit/NamedCursor.tsx +1 -1
  66. package/src/{remotion → hyperframes}/kit/Orbit3D.tsx +1 -1
  67. package/src/{remotion → hyperframes}/kit/Particles3D.tsx +1 -1
  68. package/src/{remotion → hyperframes}/kit/Place.tsx +1 -1
  69. package/src/{remotion → hyperframes}/kit/PromptBox.tsx +1 -1
  70. package/src/{remotion → hyperframes}/kit/Scene3D.tsx +2 -2
  71. package/src/{remotion → hyperframes}/kit/SceneFrame.tsx +1 -1
  72. package/src/{remotion → hyperframes}/kit/ScreenOverlay.tsx +1 -1
  73. package/src/{remotion → hyperframes}/kit/Sfx.tsx +1 -1
  74. package/src/{remotion → hyperframes}/kit/SoundCues.tsx +1 -1
  75. package/src/{remotion → hyperframes}/kit/TerminalLog.tsx +1 -1
  76. package/src/{remotion → hyperframes}/kit/Text3D.tsx +1 -1
  77. package/src/{remotion → hyperframes}/kit/TextOnImage.tsx +1 -1
  78. package/src/{remotion → hyperframes}/kit/TitleCard.tsx +1 -1
  79. package/src/{remotion → hyperframes}/kit/Voiceover.tsx +1 -1
  80. package/src/{remotion → hyperframes}/kit/Warp3D.tsx +1 -1
  81. package/src/hyperframes/kit/brand-transform.ts +25 -0
  82. package/src/{remotion → hyperframes}/kit/docs.ts +6 -2
  83. package/src/{remotion → hyperframes}/kit/index.ts +3 -0
  84. package/src/{remotion → hyperframes}/kit/sound-cues.ts +1 -1
  85. package/src/{remotion → hyperframes}/kit/sound-kinds.ts +14 -1
  86. package/src/{remotion → hyperframes}/kit/theme.ts +42 -40
  87. package/src/{remotion → hyperframes}/kit/ui-math.ts +1 -1
  88. package/src/hyperframes/math.ts +62 -0
  89. package/src/hyperframes/three.tsx +10 -0
  90. package/src/project/chromakey.ts +1 -1
  91. package/src/project/layers.ts +1 -1
  92. package/src/project/serve.ts +2 -2
  93. package/src/render/component-preview.ts +11 -55
  94. package/src/render/render.ts +62 -64
  95. package/src/render/serve.ts +31 -0
  96. package/src/render/static-check.ts +15 -4
  97. package/src/render/validate.ts +4 -4
  98. package/src/render/word-check.ts +1 -1
  99. package/src/render/worker.ts +71 -0
  100. package/src/testing/fixtures.ts +1 -1
  101. package/src/remotion/Root.tsx +0 -31
  102. /package/src/{remotion → hyperframes}/kit/Icon.tsx +0 -0
  103. /package/src/{remotion → hyperframes}/kit/beat.ts +0 -0
  104. /package/src/{remotion → hyperframes}/kit/bg-math.ts +0 -0
  105. /package/src/{remotion → hyperframes}/kit/brand-icons.ts +0 -0
  106. /package/src/{remotion → hyperframes}/kit/caption-groups.ts +0 -0
  107. /package/src/{remotion → hyperframes}/kit/caption-style.ts +0 -0
  108. /package/src/{remotion → hyperframes}/kit/image-layers-math.ts +0 -0
  109. /package/src/{remotion → hyperframes}/kit/inter-bold-typeface.ts +0 -0
  110. /package/src/{remotion → hyperframes}/kit/media.ts +0 -0
  111. /package/src/{remotion → hyperframes}/kit/motion-math.ts +0 -0
  112. /package/src/{remotion → hyperframes}/kit/music-math.ts +0 -0
  113. /package/src/{remotion → hyperframes}/kit/quiet-three.ts +0 -0
  114. /package/src/{remotion → hyperframes}/kit/sample-text.ts +0 -0
  115. /package/src/{remotion → hyperframes}/kit/scene3d-context.ts +0 -0
  116. /package/src/{remotion → hyperframes}/kit/seeded.ts +0 -0
  117. /package/src/{remotion → hyperframes}/kit/three-fx-math.ts +0 -0
  118. /package/src/{remotion → hyperframes}/kit/three-math.ts +0 -0
  119. /package/src/{remotion → hyperframes}/kit/transition-math.ts +0 -0
  120. /package/src/{remotion → hyperframes}/kit/ui-theme.ts +0 -0
  121. /package/src/{remotion → hyperframes}/kit/word-anchor.ts +0 -0
  122. /package/src/{remotion → hyperframes}/types.ts +0 -0
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: style-components
3
+ description: Map Reelkit's shared component catalog to shot roles and styles, while distinguishing pulled sibling components from built-in kit exports.
4
+ ---
5
+
6
+ # Choose a component by its job
7
+
8
+ This inventory covers the 91 shared components in the reviewed repository catalog. It is not a list of built-in kit exports or a promise that every component is published in the current account's library. Search for the role, inspect the returned match, and pull its actual id before use. `reelkit assets pull <id>` prints the import and example and puts the source in `src/`. Read its props and timing implementation before retiming it.
9
+
10
+ Import a pulled component from its sibling file. Only actual kit exports in `reference/kit.md` come from `reelkit/kit`. Do not import every component into a film or duplicate the entire catalog inside the skill. If the required component is unavailable, use a fitting kit primitive or follow `reference/component-authoring.md` to write a reusable alternative.
11
+
12
+ | Shot role | Shared components | Styles and checks |
13
+ |---|---|---|
14
+ | Notifications and results | `NotificationBanner`, `AlertDialog`, `StatusToast`, `DynamicIsland`, `HomeWidget`, `DeviceSheet`, `AppInstallCard` | Product walkthrough, AI at work, launch; trigger the actual state after the action and verify held content |
15
+ | Source screens and products | `PhoneMockup`, `BrowserMockup`, `LaptopMockup`, `TiltCard`, `ProductCard`, `AppDock` | Product and premium shots; supply real media, preserve proportions and finish in a readable pose |
16
+ | Interactions and settings | `SearchBar`, `ToggleList`, `CursorClick`, `TouchTap`, `CollabCursors`, `CallOut` | Walkthrough, tutorial, morphing UI; inspect target coordinates, response timing and crop |
17
+ | Assistant and developer work | `PromptBox`, `StreamingAnswer`, `AssistantChatWindow`, `AgentSteps`, `ShimmerSkeleton`, `GlowOrb`, `TerminalWindow`, `CodeWindow`, `IssueBoard`, `ChatThread` | AI/product films; use supplied outputs and preserve request → processing → result order |
18
+ | Steps and time | `StepList`, `Checklist`, `ProgressBars`, `Countdown`, `Timeline` | Tutorials, processes and milestones; align each state to the real instruction or source date |
19
+ | Charts and factual results | `LineChart`, `BarChart`, `AreaChart`, `PieChart`, `RadialChart`, `RadarChart`, `ComposedChart`, `StatCard`, `ComparisonSplit`, `RankingList`, `LiveScoreCard`, `PollCard`, `StarRating` | Numbers, proof and HUD; verify baseline, unit, scale, source values and final state |
20
+ | Offers and feature collections | `PricingCard`, `PriceDrop`, `BentoGrid`, `IconGrid`, `OrbitItems` | Launch, product and spatial lists; supplied price/features/marks, one focal hierarchy and readable hold |
21
+ | Brand and closing action | `LogoReveal`, `BrandSplash`, `AppIconOpen`, `CTAButton` | Logo sting and launch; preserve the actual mark and user-requested action |
22
+ | People and social evidence | `SocialHandle`, `NameLowerThird`, `QuoteCard`, `SocialPost`, `StoryFrame`, `PostFrame`, `ReelOverlay`, `CommentSticker`, `ProfileCard` | People/proof, footage, social native; exact attribution, real counts and face/platform clearance |
23
+ | Reactions and playful material | `EmojiPop`, `EmojiReactions`, `ReactionPills`, `Confetti`, `StickerBadge`, `HandDrawnMark` | Social, notebook, cel and collage; use reactions intentionally, keep them clear of speech and important text |
24
+ | Type and poster motion | `NeonText`, `KineticTitle`, `CinematicTitle`, `Marquee`, `HighlightText`, `TypewriterText`, `ScrambleText`, `BlurReveal`, `GradientText`, `WordRotate`, `GlitchText`, `WaveText`, `OutlineFillText`, `EchoText`, `PunchWords`, `CircleText`, `SpotlightText`, `StrikeReplace` | Headline, cinematic, neon, poster and mixed media; inspect reading order, complete words, RTL and final fit |
25
+ | Audio visual and atmosphere | `Waveform`, `GlowBackdrop` | Assistant, music, aurora and premium shots; distinguish decorative activity from a measured waveform and protect text contrast |
26
+
27
+ ## Kit building blocks
28
+
29
+ The kit supplies scene framing, timing and reusable geometry around those components:
30
+
31
+ - `SceneFrame`, `Entrance`, `Carry`, `Camera`: stage the action and carry a subject across shots.
32
+ - `Headline`, `WordReveal`, `Counter`, `CounterRoll`: readable type and numbers. Word timing comes from the actual speech events.
33
+ - `BrowserFrame`, `GlassPanel`, `PromptBox`, `NamedCursor`, `TerminalLog`: built-in UI primitives. The kit's `PromptBox` and a pulled component of the same name are separate APIs; use the source you actually imported.
34
+ - `Scene3D`, `BrandTransform3D`, `Hero3D`, `Screen3D`, `Card3D`, `Orbit3D`, `Text3D`, `Assemble3D`, `Particles3D`, `Warp3D`: frame-driven depth and branded transformations. Custom product geometry, rigs and Blender shaders need an external rendered asset or a separately implemented kit feature.
35
+ - `BgMesh`, `BgAurora`, `BgGrid`, `BgBeams`, `BgGrain`, `BgImage`, `BgVideo`, `BgSequence`: choose a ground that fits the style.
36
+ - `ImageLayers`, `TextOnImage`, `KenBurnsImage`, `ClipLayer`, `KeyedClip`, `FootageLayer`: layer source material without fabricating it.
37
+ - `Voiceover`, `Music`, `Sfx`, `SoundCues`, `Captions`: preserve speech, place sound on the visual event clock and honor the chosen caption mode.
38
+ - `HudOverlay`, `ScreenOverlay`, `Grade`, `Grain`, `Vignette`: use finishing only when it solves a visible problem or belongs to the look.
39
+
40
+ The detailed props and examples remain in `reference/kit.md` and the pulled source. This role map chooses a candidate; it does not verify the component's behavior in a new composition. Run the normal check and preview, inspect its action and held state, then verify the final export.
@@ -0,0 +1,86 @@
1
+ ---
2
+ name: style-recipes
3
+ description: Apply a chosen Reelkit style through a visible action, appropriate components, a shared sound clock and shot-specific verification. Covers the existing 28 looks and advanced motion treatments.
4
+ ---
5
+
6
+ # Turn the look into a shot
7
+
8
+ Read the row for the selected look, together with its detailed card in `reference/styles.md` or `reference/art-styles.md`. For advanced external production, read `reference/higgsfield-production.md`. Use `reference/style-components.md` to find an existing component before writing one. These are alternatives and ingredients; a film does not need every style.
9
+
10
+ Keep the user's brand, exact copy, source identity and approved direction. A company's reference film can inform composition, pacing, material and movement without substituting its logo, interface or claims for the user's. Preserve a real source screen when showing a product. Explain any illustrative reconstruction.
11
+
12
+ ## A compact shot contract
13
+
14
+ For each substantial new shot, put the following in the scene's notes: what it proves, source asset, focal subject, start/action/landing/hold, implementation route, spoken word or musical event, and sound cue. Describe the final readable pose before the entrance. Reuse the existing plan for a revision; add only the facts needed by that edit.
15
+
16
+ Declare the visual system once: palette, font roles, stroke and corner treatment, material/texture, light direction and motion weight. A mixed-media film can change materials while carrying a word, shape or accent through the changes. One exact universal spring or effect count cannot define all these styles.
17
+
18
+ The actual word time or agreed musical event owns meaning. Recipe timings and distances are starting points. Use the scene-local frame for motion, add `startFrame` once for global cues, and account for the chosen sound file's audible peak. Step drawing changes through a quantized clock for cel, collage and pixel work; keep exact semantic landing and SFX events on the real frame clock. Never shift a spoken event simply to fit a drawing step.
19
+
20
+ ## Existing looks: action, sound and proof
21
+
22
+ The numbers match the two existing catalogs. Use the named library families through search and pull; read the pulled source before setting its props. The kit and shared-library distinction is in `reference/style-components.md`.
23
+
24
+ | Look | Visible action and implementation | Sound and proof |
25
+ |---|---|---|
26
+ | 1. Product walkthrough | Keep the real screen in a browser/device frame; point, press, show the relevant result | Click on the press; verify target, response and readable control |
27
+ | 2. Numbers that land | Counter or chart resolves from real data; state the baseline and unit | Sparse ticks, optional result hit; check exact final value and scale |
28
+ | 3. Headline hits | Heavy type changes scale, position or width with one clear reading order | Selected impacts; inspect each landing and the full closing line |
29
+ | 4. Cinematic story | Source image/footage carries a motivated pan, close-up or hold | Quiet atmosphere or score; check crop, exposure and emotional pacing |
30
+ | 5. Neon and night | Draw a line or reveal one lit hero against a dark field | Electric swell or small buzz; keep text edges sharp and glow bounded |
31
+ | 6. Notebook | Hand-drawn annotation identifies a source detail; paper stays still | Pencil/friction; check the endpoint and frame-stable drawing variants |
32
+ | 7. Step by step | Step tracker advances as the real instruction is demonstrated | Tap on advancement; check order, spoken triggers and time to read |
33
+ | 8. People and proof | Introduce the speaker or show a sourced quote without altering it | Usually a quiet entrance; verify name, attribution and source wording |
34
+ | 9. Over footage | Overlay one explanatory item while preserving face, action and speech | Preserve source audio; inspect real speech captions and overlay exits |
35
+ | 10. Logo sting | Build toward the supplied mark and finish on that exact asset | Sweep into lock, or silence; compare final proportions and colors |
36
+ | 11. Launch film | A field, screen or product changes role across a few purposeful shots | Music phrasing and event hits; check reveal and final brand hold |
37
+ | 12. Social native | Show the real comment/post and its response in relevant platform framing | UI taps or reaction accents; verify every count and clear platform margins |
38
+ | 13. AI at work | Request, processing, supplied result; show a coherent state sequence | Submit click and result cue; verify causal order and actual product output |
39
+ | 14. Flat vector | Shape rig anticipates, moves and settles with a clear silhouette | Pops or soft cartoon accents; check pivots and the settled proportions |
40
+ | 15. Line art | Path growth connects ideas, then resolves into the intended figure | Pen sound during drawing; check continuity, corners and final path |
41
+ | 16. Isometric | Build a consistent grid, reveal parts, then show its working relationships | Small build ticks; check projection, overlap and depth order |
42
+ | 17. Soft 3D render | A studio-lit hero arrives, settles and exposes its useful surface | Soft thud; inspect contact, highlights and held front-facing content |
43
+ | 18. Hand-drawn cel | Jointed drawings move on stepped samples with deliberate smear and rest | Short cartoon cues; inspect pivots, extreme pose and deterministic boil |
44
+ | 19. Collage cut-out | Cutouts move around physical anchors over a paper composition | Paper/slap accents; inspect alpha edges, overlap and readable type |
45
+ | 20. Liquid | Blobs join, transfer volume and resolve into a stable silhouette | Gloop/splash on contact; inspect necks, midpoint and unfiltered final mark |
46
+ | 21. Shape morph | One subject interpolates compatible shapes through a readable midpoint | Sweep lands with the new form; check knotting and continuous identity |
47
+ | 22. Bauhaus grid | Geometric cells swap, slide or pivot within one strict grid | Dry rhythmic ticks; inspect shared boundaries and aligned stops |
48
+ | 23. Synthwave | Perspective grid, horizon and chrome title establish a retro scene | Synth score and selected crash; check moving grid and stable reading hold |
49
+ | 24. Aurora glass | Layer translucent panels and a restrained light field at distinct depths | Shimmer/tiny ticks; check contrast, banding and background bleed |
50
+ | 25. Variety captions | An expressive reaction lands after the real moment while speech remains readable | Comic accent under speech; verify timing, face clearance and RTL |
51
+ | 26. Sticker explainer | Camera follows isolated subjects, labels and evidence across an information canvas | Light ticks and camera sweeps; check factual scale and label occlusion |
52
+ | 27. Pixel art | Sprites and layers move in whole internal pixels on stepped drawings | Chiptune/8-bit accents; inspect integer scaling and crisp edges |
53
+ | 28. HUD | Frame lines, scan and real status resolve into one lock state | Scan/lock tone; verify actual data, hierarchy and restrained glitches |
54
+
55
+ ## Advanced treatments
56
+
57
+ These extend the catalog. They may combine with an existing look when they explain the same idea. Read the row's implementation limits before planning its result.
58
+
59
+ | Treatment | When and how it helps | Sound, proof and limits |
60
+ |---|---|---|
61
+ | 29. Morphing UI | Show one action becoming its response: field → progress → result. Use `Carry`, kit panels and frame-driven state geometry | Click initiates, lock confirms; prove that one subject persists and labels never overlap |
62
+ | 30. Particle word | An abstract network condenses into a requested Latin word. Use `Particles3D` in `Scene3D`, then the supplied flat mark for brand fidelity | Sparse rise and resolve; inspect density and final legibility. Keep unsupported scripts in 2D |
63
+ | 31. Cube world | A wave, assembly or orbit makes quantity or relationships spatial. Use `Assemble3D`, or build a verified kit component for custom motion | Build ticks follow selected events; inspect occlusion and fit. A custom wave or bouncing ball is not an automatic kit feature |
64
+ | 32. Text rings | Organize a short set of values around a focal statement. Search circle text/orbit components; author SVG text paths if the required bend is missing | Soft rotation sweep; inspect reading direction and overlap. Keep essential sentences outside the moving ring |
65
+ | 33. Children's-book cutaway | Explain a mechanism through simple drawings, windows and anchored labels | Drawing/tap cues; inspect part relationships. Use an actual rig or explicit frame-driven geometry for character motion |
66
+ | 34. Blueprint to product | Resolve a sourced technical drawing into its matching physical object. Use an inspected Blender render for exact custom geometry | Pencil draw becomes a mechanical lock; compare dimensions and matching silhouettes. A generic device mockup cannot prove bespoke geometry |
67
+ | 35. Exploded assembly | Explain how real product parts connect. Use `/exploded-view` and the verified local Blender workflow | Selected mechanical ticks and one assembly landing; inspect paths, contact, intersections and final source model |
68
+ | 36. Stylized toon 3D | Keep volume while adopting a drawn lighting/material language. Use `/cartoon-shaders` in Blender and render the authored motion | Material-appropriate accents; check contour, shadow boundaries and lighting across the camera move |
69
+ | 37. Layered poster | Animate a supplied poster through masks, type hierarchy and paper layers. Use kit media/SVG or a verified native editor workflow | Paper slide or restrained reveal; inspect reconstruction against the original and final readable composition |
70
+ | 38. Mixed-media narration | A new visual world explains each change of meaning while one graphic thread persists | Cue semantic handoffs rather than every word; check actual word timing, source truth and consistent hierarchy |
71
+ | 39. Cutout depth shot | A supplied subject overlaps foreground type and a matching background. Use inspected PNG or the supported keyed-video path | Subtle arrival/contact sound; inspect holes, spill, motion edges and light direction. A still cutout does not reconstruct hidden surfaces |
72
+ | 40. Composited VFX shot | Integrate supplied footage with authored layers in the verified `/shot-composer` workflow, then ingest the rendered shot | Respect the source's space and sound; inspect matte, grain, light, perspective and source timing. Connecting AE is a separate requirement |
73
+
74
+ ## Implement without changing engines
75
+
76
+ Reelkit uses seekable TSX and the import allowlist in `reference/hyperframes-composition.md`. Port choreography into those mechanisms. Native Higgsedit tracks, After Effects projects, Blender rigs and standalone HyperFrames HTML are separate authoring surfaces. Export inspected supported media from an external workflow; do not paste another engine's timeline API into `Video.tsx`.
77
+
78
+ Use only actual available kit props. For example, `Hero3D` owns `floor="soft"`; camera anticipation uses the camera's `lead`, not a per-key `lead`. A mood establishes kit lighting, not arbitrary Blender materials. Read `reference/kit.md` and the selected component source before promising a shader, simulation or loader.
79
+
80
+ ## Review the style in the final video
81
+
82
+ Inspect opening, strongest change, landing, readable hold and ending; add boundary samples for morphs, masks and overlaps. Direct-seek to those states to expose accumulated-state bugs. For real depth, inspect an angle where occlusion and perspective are visible. For cutouts, inspect light and dark backgrounds and moving edges. For stepped motion, confirm the drawing cadence without quantizing away semantic or sound events.
83
+
84
+ Listen to the export for intelligible source speech, chosen music and synchronized cues. Restore the actual brand asset for the final hold. Fix the largest observed failure and recheck that moment. Do not certify a style with a numerical taste score or a static screenshot alone; report checks actually performed using `reference/delivery-review.md`.
85
+
86
+ This playbook adapts the user's supplied studio-editing reference and the reviewed [Higgsfield workflows](https://higgsfield.ai/skills) and [official HyperFrames skills](https://github.com/heygen-com/hyperframes/tree/main/skills). The original art-style provenance stays in `reference/art-styles.md` and `THIRD_PARTY.md`.
@@ -1,16 +1,18 @@
1
1
  ---
2
2
  name: styles
3
- description: Use before planning, to choose the video's look with the user - the two modes (restrained and showreel) and a catalogue of looks, each with when to use it, how it is built, and what it forbids.
3
+ description: Choose a visual language from the material or the user's direction, with restrained and showreel approaches and a catalog of look-specific techniques.
4
4
  ---
5
5
 
6
6
  # Choosing the look
7
7
 
8
- Pick one look for the whole video before writing the plan, and say it in the first scene's `notes`. A video that mixes looks reads as a template.
8
+ Choose a visual language that fits the material and record it in the first scene's `notes`. Brand films usually benefit from one system; a narration-driven mixed-media film can change worlds by meaning while retaining a thread of type, accent or object. Read `reference/studio-editing.md` when the approach is still open.
9
9
 
10
- If the user already described what they want, match it to a look and confirm in one sentence. Otherwise offer the catalogue below as a short numbered list with one line each, and include "your own: describe it, or send a picture or a link". Ask every open question in one message, each with a default, so the user can answer "defaults".
10
+ Use the user's chosen direction. Otherwise recommend a fitting look with a short reason; use the catalogue as technique references, not a mandatory menu. Offer alternatives when requested. Ask only about consequential missing information.
11
+
12
+ After choosing the look, use `reference/style-recipes.md` to connect its visible action, implementation, sound and review evidence. `reference/style-components.md` maps all reviewed shared components to their roles. The catalog's timing, palette and exclusions are defaults for the described treatment; real speech timing, supplied brand identity, the user's requested variation and the installed runtime take precedence.
11
13
 
12
14
  ## Two modes
13
- Every look belongs to one mode. The mode decides which rules in `reference/motion-design.md` bend.
15
+ Restrained and showreel describe motion energy, not separate engines. Choose the energy by the shot's purpose; a mixed-media film can combine them while preserving its visual thread. The chosen treatment explains which craft defaults in `reference/motion-design.md` change.
14
16
 
15
17
  **Restrained** (product demos, explainers, anything that must feel expensive and calm)
16
18
  - One background, one hero colour or black and white, one face.
@@ -19,8 +21,8 @@ Every look belongs to one mode. The mode decides which rules in `reference/motio
19
21
 
20
22
  **Showreel** (openers, announcements, anything that must stop the scroll)
21
23
  - Hard cuts on the beat between full-colour backgrounds; type that fills the frame. Flat solid colour fields are right here.
22
- - The camera never stops: a slow push, a slight turn, a short shake on each hit.
23
- - No frame sits still longer than a third of a second, except the final hold.
24
+ - Camera movement and brief impact shakes can reinforce selected hits. Keep reading moments stable.
25
+ - Pace changes by meaning and musical phrasing, allowing deliberate holds rather than moving every frame.
24
26
  - At most three full-screen flashes in any second, and never a red strobe. This is a safety rule, not a taste rule.
25
27
 
26
28
  ## The catalogue
@@ -33,7 +35,7 @@ Each look is built from what the kit and the shared library already hold, so mos
33
35
  **When:** results, growth, a comparison, anything with figures from the narration. **How:** one figure or one chart per scene (search "statistic counter", "line chart", "bar chart", "pie chart", "radial gauge"); the number counts up and finishes before the scene's midpoint; a before and after sits side by side (search "comparison"). The payoff number gets the biggest move of the video. **Forbidden:** any figure that is not in the plan, two charts in one frame, decorative data.
34
36
 
35
37
  ### 3. Headline hits (showreel)
36
- **When:** an opener, a launch, a message of a few words that must stop the scroll. **How:** one or two words fill the frame (search "kinetic title"), hard cuts to a new full colour on the beat, each word entering a different way, and the whole message together at the end, held. The camera keeps a slow push the whole time. **Forbidden:** soft gradients, outlined words, a still frame before the final hold.
38
+ **When:** an opener, a launch, a message of a few words that must stop the scroll. **How:** one or two words fill the frame (search "kinetic title"), selected hard cuts to a full colour on a musical or spoken event, and the whole message together at the end, held. Vary the entrance when it helps hierarchy; keep one motion language. A camera push is optional. **Avoid for this treatment:** gradients or outlines that soften the intended heavy graphic read, and motion that prevents reading the landing.
37
39
 
38
40
  ### 4. Cinematic story (restrained)
39
41
  **When:** a mood, a place, a story told by a voice. **How:** generated or reused pictures with a slow move across them, a film grade and grain over everything, a poster-style title to open (search "cinematic title"), a film overlay if it suits (`--kind overlay`, search "film"). Few words on screen; the captions carry the text. **Forbidden:** interface parts, bright accent colours, fast cuts.
@@ -51,13 +53,13 @@ Each look is built from what the kit and the shared library already hold, so mos
51
53
  **When:** a testimonial, an introduction, a creator talking, social proof. **How:** the person's name and role in a lower third (search "name lower third"), a quote card with its stars (search "quote testimonial"), a follow line to close (search "social handle", "cta button"). Quotes and names come from the user, word for word. **Forbidden:** an invented quote, rating or follower count.
52
54
 
53
55
  ### 9. Over footage (either mode)
54
- **When:** the user supplied their own video. **How:** the footage is the picture; graphics are guests. One overlay at a time, clear of the speaker's face; a small punch-in on each sentence's key word; lower thirds and callouts from the library; captions always. **Forbidden:** covering the face, a graphic left on screen after its sentence, zooms on footage that already has its own.
56
+ **When:** the user supplied their own video. **How:** the footage is the picture; graphics support it. Keep the active graphic clear of the speaker's face; use a punch-in only for needed emphasis or framing, with lower thirds and callouts from the library. Honor the user's caption choice and use actual source-speech timings (`reference/studio-editing.md`). **Avoid:** covering the face, a graphic left after its purpose ends, zooms stacked on footage that already has its own.
55
57
 
56
58
  ### 10. Logo sting (either mode)
57
59
  **When:** an opener or end card, from the user's own logo file. **How:** build toward the logo from its own shapes and colours and land on it exactly as supplied, held at least 1.5 seconds. **Forbidden:** redrawing, recolouring or stretching the logo; anyone else's logo or trademark.
58
60
 
59
61
  ### 11. Launch film (restrained)
60
- **When:** a product, app or feature launch for a tech, software or AI brand: the short film that opens a launch post. **How:** a clean off-white or near-black ground with one soft pool of the hero colour at an edge (search "glow backdrop"); one object in the middle of each shot and a lot of empty space around it. Open on a single line of small, calm type that comes into focus word by word (search "blur reveal"), then one idea per shot, each 1.5 to 2.5 seconds: a field being typed into (search "search bar", "prompt box"), the real screenshot on a card floating at a slight tilt (search "tilt card", "laptop mockup", "phone mockup"), tiles circling a short line (search "orbit"), a feature grid (search "bento"), a pointer that clicks through it (search "cursor click"), the one real number as the payoff (search "statistic counter"), and the logo small and centred to close (search "logo reveal", "brand splash"). Between shots the outgoing object leaves fast with a short directional blur and the next one arrives on a heavy spring; the camera pushes in 2 to 4 percent on every shot. Six to eight shots in 12 to 20 seconds, music without a voice or with very few words. This look opens small on purpose: the first object may fill only a fifth of the frame, as long as the push carries it larger. **Forbidden:** two objects competing in one shot, a busy or textured background, a second accent colour, an invented screen, a shot that holds still, and any brand's mark but the user's own.
62
+ **When:** a product, app or feature launch for a tech, software or AI brand: the short film that opens a launch post. **How:** a clean off-white or near-black ground with one soft pool of the hero colour at an edge (search "glow backdrop"); one object in the middle of each shot and a lot of empty space around it. Open on a single line of small, calm type that comes into focus word by word (search "blur reveal"), then one idea per shot, each 1.5 to 2.5 seconds: a field being typed into (search "search bar", "prompt box"), the real screenshot on a card floating at a slight tilt (search "tilt card", "laptop mockup", "phone mockup"), tiles circling a short line (search "orbit"), a feature grid (search "bento"), a pointer that clicks through it (search "cursor click"), the one real number as the payoff (search "statistic counter"), and the logo small and centred to close (search "logo reveal", "brand splash"). Between shots the outgoing object leaves fast with a short directional blur and the next one arrives on a heavy spring; the camera pushes in 2 to 4 percent on every shot. Six to eight shots in 12 to 20 seconds, music without a voice or with very few words. This look opens small on purpose: the first object may fill only a fifth of the frame, as long as the push carries it larger. **Forbidden:** two objects competing in one shot, a busy or textured background, a second accent colour, an invented screen, an unreadable hold, and a third-party mark unrelated to the material.
61
63
 
62
64
  ### 12. Social native (showreel)
63
65
  **When:** the video should feel like it was made inside the app it is posted to: a reply to a comment, a reaction, proof from the user's own account. **How:** the picture is footage or a generated image and the graphics are the platform's own furniture, used honestly: the comment being answered at the top (search "comment sticker"), a post or a story in its frame (search "post frame", "story frame"), the reel's own buttons over the picture (search "reel overlay"), a profile with a Follow button to close (search "profile card"), reactions floating up on the payoff (search "emoji reactions", "emoji pop"), and words punching in one at a time on the voice (search "punch words"). Emoji are allowed in this look, as reactions and stickers only. **Forbidden:** an invented comment, post, follower count or like count; a platform's logo when the video is not about that platform; emoji standing in for a logo or an icon.
@@ -65,8 +67,13 @@ Each look is built from what the kit and the shared library already hold, so mos
65
67
  ### 13. AI at work (restrained)
66
68
  **When:** an AI product, an assistant or an automation: the viewer should watch it think and deliver. **How:** near-black ground; the request typed into a glowing field and sent (search "prompt box", "assistant chat window"); the work shown as steps that spin and tick (search "agent steps") or as a placeholder that resolves into the result (search "shimmer skeleton"); the answer streaming in (search "streaming answer"); a calm orb when it listens or speaks (search "glow orb"). One glow, on the field or the orb, never both in one frame. Every answer on screen is the product's real output, supplied by the user. **Forbidden:** an answer the product did not give, a second glowing element, sparkles as decoration, text that streams faster than it can be read.
67
69
 
70
+ ## Fifteen art styles (14 to 28)
71
+ `reference/art-styles.md` continues this list with fifteen looks whose picture is drawn in code rather than built from interface parts, adapted from the mg-styles-15 films: 14 flat vector, 15 line art, 16 isometric, 17 soft 3D render, 18 hand-drawn cel, 19 collage cut-out, 20 liquid, 21 shape morph, 22 Bauhaus grid, 23 synthwave, 24 aurora glass, 25 variety captions, 26 sticker explainer, 27 pixel art, 28 HUD. Use them as technique references, and read that file when the brief needs a style in that family (a drawn explainer, a line-art logo, an isometric city, "80s", "pixel", "glass", a kinetic poster). Each card there says which motion rules the look is allowed to bend.
72
+
68
73
  ## Your own
69
- Ask what the message is, what happens on screen, the colours, the length and shape, and for an example if they have one. Choose the nearest look above as the technical base and write a four-line brief in the same shape (when, how, forbidden, structure). Show the brief with the plan at the checkpoint.
74
+ Use the supplied message, actions, colours, duration and format. Ask only for consequential missing details or a reference that the choice depends on. Choose the nearest look above as the technical base and write a four-line brief in the same shape (when, how, forbidden, structure). Show the brief with the plan at the checkpoint.
75
+
76
+ For morphing UI, particle words, cube worlds, text rings, children's-book cutaways, blueprint-to-product shots, exploded assembly, toon materials, layered posters, mixed-media narration, cutout depth and composited VFX, use the advanced rows 29 to 40 in `reference/style-recipes.md`. Select a local kit or external production route that can actually deliver the shot.
70
77
 
71
78
  ## What every look shares
72
79
  - The plan checkpoint lists the exact words that will appear on screen and when. Fixing a list takes a minute; fixing a finished animation takes an hour.
@@ -5,21 +5,22 @@ description: Use when a shot needs real depth - extruded type, a screen floating
5
5
 
6
6
  # 3D shots
7
7
 
8
- The kit has a 3D layer on three.js: `Scene3D`, `Text3D`, `Card3D` and `Orbit3D`, and five more elements for the moments in a film that earn them: `Assemble3D`, `Particles3D`, `Hero3D`, `Screen3D` and `Warp3D`. Everything is deterministic and driven by the frame. You import only from `reelkit/kit`; three itself is not importable from the composition.
8
+ The kit has a 3D layer on three.js: `Scene3D`, `Text3D`, `Card3D` and `Orbit3D`, and elements for the moments in a film that earn them: `Assemble3D`, `BrandTransform3D`, `Particles3D`, `Hero3D`, `Screen3D` and `Warp3D`. Everything is deterministic and driven by the frame. You import only from `reelkit/kit`; three itself is not importable from the composition.
9
9
 
10
10
  ## When 3D earns its place
11
11
 
12
12
  One hero moment in a film: the product's name landing as thick letters, a screen floating in space and turning to face the viewer, a ring of features that the camera pushes through. That is what the extra depth is for.
13
13
 
14
- It reads as a template when everything spins, when several objects each get their own 3D entrance, or when body text is extruded. Type that is read in a sentence stays 2D. Keep 3D to one or two shots in a film, and let the rest be flat and fast.
14
+ It reads as a template when everything spins, when several objects each get their own 3D entrance, or when body text is extruded. Type that is read in a sentence stays 2D. One or two 3D shots usually provide enough contrast. A requested brand film or showreel can use more when each has a distinct purpose; keep sentences and detailed screens readable.
15
15
 
16
16
  ## Which element earns its place
17
17
 
18
- One 3D moment per film is usually enough. Choose by what the moment has to say:
18
+ Choose by what the moment has to say. For a brand transformation and its matching sound, read `reference/brand-motion.md`:
19
19
 
20
20
  | The moment | Reach for | Why |
21
21
  |---|---|---|
22
22
  | A reveal: the name, a logo, a number of things arriving | `Assemble3D` (`shape="text"` for a word, `"grid"`, `"sphere"`, `"wall"`, `"ring"`) | Hundreds of blocks build into the thing; the piece counter (`assembledCount`) and the lock sound (`assembleEnd`) come with it |
23
+ | A brand or product arriving in its readable pose | `BrandTransform3D` (`mode="turn"`, `"arc"`, `"launch"`) | One deterministic arrival that holds neutral; `brandTransformFrames` gives the exact sound landing |
23
24
  | An abstract idea: intelligence, flow, a network, "everything in one place" | `Particles3D` (`from` and `to` shapes, or `"text"`) | Light that changes shape reads as thought, and costs no artwork |
24
25
  | The product itself | `Hero3D` (`kind="device"` with a screenshot, `"logo"`, `"coin"`, `"box"`) | A studio-lit object with clearcoat, two coloured rim lights and a soft floor |
25
26
  | An interface carried across scenes | `Screen3D` with `poses` | One screen, re-posed at each scene, instead of a new mock each time |
@@ -27,7 +28,7 @@ One 3D moment per film is usually enough. Choose by what the moment has to say:
27
28
 
28
29
  Set the mood once on the `Scene3D` (`mood="studio"`, `"night"`, `"sunset"` or `"neon"`): it chooses the light colours, their intensities and the fog tint together, so nobody tunes lights by hand. Everything fits a 9:16 frame by default (`fit`, the share of the width at the closest the camera comes), and everything is a pure function of the frame and a `seed`.
29
30
 
30
- Cost, measured on this machine (software GL, as every render here): one second (30 frames) of 9:16 at 1080 by 1920 took about 1.4 to 1.9 seconds to render for each of them at its default size: `Assemble3D` of 600 blocks 1.9 s, 700 blocks 1.7 s, a 900-block word 1.5 s; `Particles3D` of 12000 points 1.5 to 1.8 s; `Hero3D` and `Screen3D` 1.4 to 1.5 s; `Warp3D` of 500 streaks 1.6 s. That includes the start of the renderer, so a longer shot costs less per second; a 3D shot is not what makes a film slow, but keep `count` at what the picture needs (`Assemble3D` up to 4000 pieces, `Particles3D` up to 60000 points, both of which cost more in proportion).
31
+ HyperFrames captures 3D through software GL for consistent output. Render cost depends on the browser, resolution, geometry and other jobs on the machine; measure the actual shot instead of relying on timings from a previous renderer. Start with the count the picture needs and raise it only when the preview improves.
31
32
 
32
33
  ## How to layer it
33
34
 
@@ -47,7 +48,7 @@ So on a phone frame the camera sees about 3 units across at z 6, not 5.5; a card
47
48
 
48
49
  ## Sizes: leave them out
49
50
 
50
- `Text3D` without `size` is sized from the measured width of its own letters so that it fills `fit` of the frame's width (default 0.8) at the closest the camera comes to it. "Closest" is read from the `Scene3D` camera keys: the key where it sees the least. A word is therefore whole at every moment, on any aspect, and exactly as big as it can be. A line break (`\n`) makes a second line; its height is held to `fit` of the frame's height. Giving `size` turns this off and you are back to doing the arithmetic yourself.
51
+ `Text3D` without `size` is sized from the measured width of its own letters so that it fills `fit` of the frame's width (default 0.8) at the closest the camera comes to it. "Closest" is read from the `Scene3D` camera keys: the key where it sees the least. A word is therefore whole at every moment, on any aspect, and exactly as big as it can be. A line break makes a second line: write `text={"Hyper\nFrames"}` in JSX, since `text="Hyper\nFrames"` passes a literal backslash and n; its height is held to `fit` of the frame's height. Giving `size` turns this off and you are back to doing the arithmetic yourself.
51
52
 
52
53
  A push-in makes the word smaller at the start in proportion: from z 9 to z 6 it begins at two thirds of its final width. A start at about 25 percent further away than the end (z 7.5 to 6) reads as a gentle push; a larger one begins as a small word. Camera sideways moves (`x`) are not counted, so keep the word near the middle when you orbit.
53
54
 
@@ -83,7 +84,7 @@ A word and a ring of labelled cards on a phone frame. Nothing is sized by hand,
83
84
 
84
85
  ```tsx
85
86
  import React from "react";
86
- import { AbsoluteFill } from "remotion";
87
+ import { AbsoluteFill } from "reelkit/frame";
87
88
  import { Card3D, Orbit3D, Scene3D, SceneFrame, Text3D, palettes } from "reelkit/kit";
88
89
  import type { VideoProps } from "reelkit/kit";
89
90
 
@@ -114,7 +115,7 @@ The name arrives as blocks that fly out of a cloud and settle into the letters,
114
115
 
115
116
  ```tsx
116
117
  import React from "react";
117
- import { AbsoluteFill } from "remotion";
118
+ import { AbsoluteFill } from "reelkit/frame";
118
119
  import { Assemble3D, Scene3D, SceneFrame, palettes } from "reelkit/kit";
119
120
  import type { VideoProps } from "reelkit/kit";
120
121
 
@@ -52,7 +52,7 @@ The composition. The number finishes counting as "thousand" is said, and each ro
52
52
 
53
53
  ```tsx
54
54
  import React from "react";
55
- import { AbsoluteFill, Sequence, useVideoConfig } from "remotion";
55
+ import { AbsoluteFill, Sequence, useVideoConfig } from "reelkit/frame";
56
56
  import { Captions, Counter, Entrance, Music, onWord, SceneFrame, sceneById, Sfx, Voiceover, wordFrame } from "reelkit/kit";
57
57
  import type { VideoProps } from "reelkit/kit";
58
58
 
@@ -0,0 +1,111 @@
1
+ import { expect, test } from 'claude-code/testing'
2
+
3
+ const DIR = '/work/demo'
4
+ const PANE = { title: 'Reelkit', isFocused: false, bodyColumns: 100, placement: 'dock', scroll: { offset: 0, bodyRows: 40 }, view: {} } as const
5
+
6
+ const FILES: Record<string, string> = {
7
+ [`${DIR}/reelkit.json`]: JSON.stringify({ name: 'demo', aspect: '9:16' }),
8
+ [`${DIR}/plan.json`]: JSON.stringify({
9
+ title: 'Demo film',
10
+ aspect: '9:16',
11
+ voiceId: 'v-1',
12
+ scenes: [
13
+ { id: 'hook', narration: 'First the hook lands.', treatment: 'motion-graphic', onScreenText: ['HOOK'] },
14
+ { id: 'proof', narration: 'Then the proof follows.', treatment: 'illustration', onScreenText: ['PROOF'] },
15
+ ],
16
+ }),
17
+ [`${DIR}/manifest.json`]: JSON.stringify({
18
+ fps: 30,
19
+ totalFrames: 240,
20
+ music: { key: 'assets/lib/music-a/track.mp3', bpm: 120, beatFrames: [0, 15, 30, 45] },
21
+ scenes: [
22
+ { id: 'hook', startFrame: 0, durationFrames: 90, words: [{ word: 'First', startSec: 0.1, endSec: 0.4 }] },
23
+ { id: 'proof', startFrame: 90, durationFrames: 150, words: [{ word: 'Then', startSec: 0.2, endSec: 0.5 }] },
24
+ ],
25
+ }),
26
+ [`${DIR}/assets/music.json`]: JSON.stringify({ key: 'assets/lib/music-a/track.mp3', title: 'Track A', durationSec: 20 }),
27
+ [`${DIR}/src/Badge.tsx`]: '// A round badge with one word in it. Use it to mark a claim.\nexport const Badge = () => null\n',
28
+ }
29
+
30
+ const entry = (name: string) => ({ name, kind: 'file' as const, size: 10, mtimeMs: 1000, isLink: false })
31
+
32
+ // The engine beneath the mod: one project on disk, a render, and commands that answer from memory.
33
+ type TestOn = Parameters<Extract<Parameters<typeof test>[1], (...args: never[]) => unknown>>[1]
34
+
35
+ const project = (on: TestOn, written: Record<string, string>, ran: string[][]) => {
36
+ on('session.cwd', () => ({ value: DIR }))
37
+ on('clock.now', () => ({ value: 3600000 }))
38
+ on('ui.open', () => ({ value: { isPlaced: true as const } }))
39
+ on('fs.exists', (_$, e) => ({ value: e.path in FILES }))
40
+ on('fs.read', (_$, e) => {
41
+ const text = FILES[e.path]
42
+ if (text === undefined) throw new Error(`ENOENT ${e.path}`)
43
+ return { value: text }
44
+ })
45
+ on('fs.list', (_$, e) => ({ value: e.path === `${DIR}/src` ? [entry('Badge.tsx'), entry('Video.tsx')] : [] }))
46
+ on('fs.stat', (_$, e) => {
47
+ if (e.path !== `${DIR}/out/video.mp4`) throw new Error(`ENOENT ${e.path}`)
48
+ return { value: { kind: 'file' as const, size: 2097152, mtimeMs: 5000, isLink: false } }
49
+ })
50
+ on('fs.write', (_$, e) => {
51
+ written[e.path] = e.text
52
+ return { value: undefined }
53
+ })
54
+ on('process.run', (_$, e) => {
55
+ ran.push([...e.argv])
56
+ const stdout =
57
+ e.argv[0] === 'reelkit'
58
+ ? JSON.stringify({ ok: true, data: { items: [{ id: 'music-b', kind: 'music', title: 'Track B', description: 'Bright.', match: 0.8, meta: { bpm: 100 } }] } })
59
+ : ''
60
+ return { value: { exitCode: 0, stdout, stderr: '', isStdoutTruncated: false, isStderrTruncated: false } }
61
+ })
62
+ }
63
+
64
+ test('the pane shows the film as a timeline on every surface', async ($, on) => {
65
+ project(on, {}, [])
66
+ for (const surface of ['terminal', 'desktop', 'vscode', 'mobile'] as const) {
67
+ const ui = await $.ui.mount({ plugin: 'reelkit', surface, component: 'Pane', requestId: 'reelkit-studio', props: PANE })
68
+ await ui.press({ key: 'refresh' })
69
+ expect(await ui.find({ type: 'Text', text: /Demo film/ })).toBeDefined()
70
+ expect(await ui.find({ type: 'Text', text: /1\. hook/ })).toBeDefined()
71
+ if (surface === 'terminal') expect(await ui.find({ type: 'Text', text: /1 hook/ })).toBeDefined()
72
+ else expect(await ui.find({ type: 'Svg' })).toBeDefined()
73
+ await ui.press({ key: 'next' })
74
+ expect(await ui.find({ type: 'Text', text: /2\. proof/ })).toBeDefined()
75
+ await ui.press({ key: 'prev' })
76
+ await ui.unmount()
77
+ }
78
+ })
79
+
80
+ test('the tabs show the plan, the music and the components', async ($, on) => {
81
+ project(on, {}, [])
82
+ for (const surface of ['terminal', 'desktop'] as const) {
83
+ const ui = await $.ui.mount({ plugin: 'reelkit', surface, component: 'Pane', requestId: 'reelkit-studio', props: PANE })
84
+ await ui.press({ key: 'refresh' })
85
+ await ui.press({ key: 'tab-plan' })
86
+ expect((await ui.find({ type: 'Markdown' }))?.props.text).toContain('Then the proof follows.')
87
+ await ui.press({ key: 'tab-music' })
88
+ expect(await ui.find({ type: 'Text', text: /Track A/ })).toBeDefined()
89
+ await ui.press({ key: 'tab-components' })
90
+ expect(await ui.find({ type: 'Text', text: /round badge/ })).toBeDefined()
91
+ await ui.press({ key: 'tab-timeline' })
92
+ await ui.unmount()
93
+ }
94
+ })
95
+
96
+ test('the browser tab searches the library and the player page is written beside the render', async ($, on) => {
97
+ const written: Record<string, string> = {}
98
+ const ran: string[][] = []
99
+ project(on, written, ran)
100
+ const ui = await $.ui.mount({ plugin: 'reelkit', surface: 'desktop', component: 'Pane', requestId: 'reelkit-studio', props: PANE })
101
+ await ui.press({ key: 'refresh' })
102
+ await ui.press({ key: 'player' })
103
+ expect(written[`${DIR}/out/studio.html`]).toContain('video.mp4')
104
+ expect(ran.some(argv => argv[0] === 'open' && argv[1] === `${DIR}/out/studio.html`)).toBe(true)
105
+ await ui.press({ key: 'tab-browser' })
106
+ await ui.input({ key: 'query', text: 'bright' })
107
+ expect(ran.some(argv => argv.join(' ') === 'reelkit assets search bright --kind music --json')).toBe(true)
108
+ expect(await ui.find({ type: 'Text', text: /80% Track B/ })).toBeDefined()
109
+ await ui.press({ key: 'tab-timeline' })
110
+ await ui.unmount()
111
+ })
@@ -0,0 +1,65 @@
1
+ export type StudioTab = 'timeline' | 'plan' | 'music' | 'components' | 'browser'
2
+
3
+ export type FilmScene = {
4
+ id: string
5
+ // Frames from the film's start, and the scene's own length in frames.
6
+ start: number
7
+ frames: number
8
+ narration: string
9
+ text: string[]
10
+ treatment: string
11
+ notes: string
12
+ // Seconds from the scene's start at which each spoken word begins.
13
+ words: number[]
14
+ // A small picture of the scene under out/.studio, when a preview frame exists.
15
+ thumb: string
16
+ }
17
+
18
+ export type FilmSound = { id: string; kind: string; title: string; path: string; seconds: number }
19
+
20
+ export type FilmComponent = { name: string; path: string; about: string }
21
+
22
+ export type Film = {
23
+ dir: string
24
+ name: string
25
+ title: string
26
+ aspect: string
27
+ fps: number
28
+ totalFrames: number
29
+ // True once manifest.json gave real timings; false while they are estimated from the plan.
30
+ isTimed: boolean
31
+ voice: string
32
+ pace: string
33
+ captions: string
34
+ scenes: FilmScene[]
35
+ music: { title: string; path: string; bpm: number; seconds: number; beats: number[] } | null
36
+ sounds: FilmSound[]
37
+ components: FilmComponent[]
38
+ userAssets: { id: string; kind: string; name: string; about: string }[]
39
+ render: { path: string; bytes: number; at: number } | null
40
+ previews: number
41
+ loadedAt: number
42
+ }
43
+
44
+ export type LibraryItem = { id: string; kind: string; title: string; about: string; match: number; detail: string }
45
+
46
+ export type LibrarySearch = {
47
+ kind: string
48
+ query: string
49
+ status: 'idle' | 'busy' | 'done' | 'failed'
50
+ note: string
51
+ items: LibraryItem[]
52
+ }
53
+
54
+ declare module 'claude-code' {
55
+ interface PluginState {
56
+ reelkit: {
57
+ tab: StudioTab
58
+ film: Film | null
59
+ projects: string[]
60
+ scene: number
61
+ component: string
62
+ search: LibrarySearch
63
+ }
64
+ }
65
+ }
@@ -9,13 +9,14 @@ import { GreenTooDullError, keyGreen } from "../project/chromakey";
9
9
  import { buildManifest, sentenceGaps, voiceoverStale, type ClipRecord, type Voiceover } from "../project/manifest";
10
10
  import { loadPlan } from "./plan";
11
11
  import { FILE_NAME } from "../render/validate";
12
+ import { migrateFrameImports } from "../render/static-check";
12
13
  import { levelOf } from "../project/loudness";
13
14
  import { beatReport, measureMusic, type MusicRecord } from "../project/music";
14
15
  import { audioDuration } from "../project/refmeasure";
15
16
  import { BACKGROUND_CLIP_SENTENCE, BACKGROUND_IMAGE_SENTENCE, isVideoPath, lookFromNotes, readBackground, setBackground } from "../project/background";
16
17
  import { probeFile } from "../project/probe";
17
18
  import { frameWithAlpha, measureTextZone, stillToVideo, tempDir, type LayerEntry } from "../project/layers";
18
- import { coverageVerdict } from "../remotion/kit/image-layers-math";
19
+ import { coverageVerdict } from "../hyperframes/kit/image-layers-math";
19
20
  import { svgProblem } from "../project/svgcheck";
20
21
  import { FILES, isPrivateProject, openProject, type Project } from "../project/project";
21
22
 
@@ -296,6 +297,9 @@ export async function assetsPull(ctx: Ctx, id: string, opts: { scene?: string; f
296
297
  const path = `src/${pulled.filename}`;
297
298
  if (project.exists(path) && !opts.force) return { ok: false, summary: `${path} already exists. Use --force to replace it with the library version.` };
298
299
  await download(pulled.url, project.path(path));
300
+ const source = readFileSync(project.path(path), "utf8");
301
+ const migrated = migrateFrameImports(source);
302
+ if (migrated !== source) writeFileSync(project.path(path), migrated);
299
303
  recordPull(project, id, { path, kind: "component", title: pulled.item.title, meta: pulled.item.meta });
300
304
  const name = pulled.filename.replace(/\.tsx$/, "");
301
305
  const example = typeof pulled.item.meta.example === "string" ? `\nExample: ${pulled.item.meta.example}` : "";
@@ -14,7 +14,7 @@
14
14
  // - A library item `id` (pull, commit) matches `^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$`; a `deviceCode` is 1 to 200 characters of plain text.
15
15
  // - A `voiceId` is 1 to 64 letters and digits and must be one of the voices the server lists (`voices`), otherwise 400 invalid_request.
16
16
  // - A user's component is uploaded for review through the same two calls as any other file (`kind: "component"`). The server checks its source
17
- // at commit with the same static check a pulled component gets (only react, remotion and reelkit/kit imports, no network, no globals that reach
17
+ // at commit with the same static check a pulled component gets (only react, reelkit/frame and reelkit/kit imports, no network, no globals that reach
18
18
  // outside the video) and refuses a source that fails it with 400 `invalid_request` and the first problem. It stays in `review`, is never found
19
19
  // by search or the public listing, and is published only by the owner. A component upload is: `contentType` `text/plain`, `bytes` up to 65,536,
20
20
  // `shareable` true, `filename` matching `^[A-Z][A-Za-z0-9]*\.tsx$`, a `description` of at least 20 characters, and `meta.example` a string of at most
@@ -0,0 +1 @@
1
+ export { mountVideo, mountVideo as makeRoot } from "./host";
@@ -0,0 +1,54 @@
1
+ import { delayRender, continueRender } from "./frame";
2
+ const loaded = new Set<string>();
3
+ export function loadFont(family: string, slug: string) {
4
+ if (typeof document !== "undefined" && !loaded.has(slug)) {
5
+ loaded.add(slug);
6
+ const handle = delayRender(`font ${family}`);
7
+ const link = document.createElement("link");
8
+ link.onload = () => continueRender(handle);
9
+ link.onerror = () => { continueRender(handle); throw new Error(`Font stylesheet failed: ${slug}`); };
10
+ link.rel = "stylesheet"; link.href = `./fonts/${slug}.css`; document.head.appendChild(link);
11
+ }
12
+ return { fontFamily: `"${family}"` };
13
+ }
14
+ export const fontFamilies = {
15
+ "Inter": "inter",
16
+ "Sora": "sora",
17
+ "ArchivoBlack": "archivo-black",
18
+ "BebasNeue": "bebas-neue",
19
+ "GreatVibes": "great-vibes",
20
+ "JetBrainsMono": "jetbrains-mono",
21
+ "Kanit": "kanit",
22
+ "Modak": "modak",
23
+ "Montserrat": "montserrat",
24
+ "Roboto": "roboto",
25
+ "RobotoSlab": "roboto-slab",
26
+ "Sacramento": "sacramento",
27
+ "Unbounded": "unbounded",
28
+ "BungeeShade": "bungee-shade",
29
+ "Cinzel": "cinzel",
30
+ "Creepster": "creepster",
31
+ "Heebo": "heebo",
32
+ "KaushanScript": "kaushan-script",
33
+ "LilitaOne": "lilita-one",
34
+ "MrsSaintDelafield": "mrs-saint-delafield",
35
+ "Orbitron": "orbitron",
36
+ "Outfit": "outfit",
37
+ "PermanentMarker": "permanent-marker",
38
+ "PlayfairDisplay": "playfair-display",
39
+ "Rubik": "rubik",
40
+ "Rye": "rye",
41
+ "Syne": "syne",
42
+ "Yellowtail": "yellowtail",
43
+ "Alef": "alef",
44
+ "AmaticSC": "amatic-sc",
45
+ "Assistant": "assistant",
46
+ "DavidLibre": "david-libre",
47
+ "FrankRuhlLibre": "frank-ruhl-libre",
48
+ "Fredoka": "fredoka",
49
+ "Karantina": "karantina",
50
+ "NotoSansHebrew": "noto-sans-hebrew",
51
+ "SecularOne": "secular-one",
52
+ "SuezOne": "suez-one",
53
+ "VarelaRound": "varela-round"
54
+ } as const;