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.
- package/README.md +13 -1
- package/package.json +49 -10
- package/skill/.claude-plugin/plugin.json +7 -0
- package/skill/SKILL.md +44 -19
- package/skill/THIRD_PARTY.md +37 -5
- package/skill/commands/launch-film.md +1 -1
- package/skill/hooks/hooks.json +1 -0
- package/skill/hooks/player.ts +278 -0
- package/skill/hooks/project.ts +227 -0
- package/skill/hooks/register.tsx +533 -0
- package/skill/hooks/timeline.ts +218 -0
- package/skill/reference/art-styles.md +70 -0
- package/skill/reference/backgrounds.md +1 -1
- package/skill/reference/brand-motion.md +62 -0
- package/skill/reference/clips.md +3 -3
- package/skill/reference/component-authoring.md +3 -1
- package/skill/reference/continuity.md +5 -5
- package/skill/reference/delivery-review.md +40 -0
- package/skill/reference/hebrew-rtl.md +3 -4
- package/skill/reference/higgsfield-production.md +70 -0
- package/skill/reference/{remotion-composition.md → hyperframes-composition.md} +14 -8
- package/skill/reference/kit.md +7 -3
- package/skill/reference/launch-film.md +13 -9
- package/skill/reference/motion-design.md +26 -22
- package/skill/reference/sound-design.md +34 -12
- package/skill/reference/studio-editing.md +55 -0
- package/skill/reference/studio-pane.md +31 -0
- package/skill/reference/style-components.md +40 -0
- package/skill/reference/style-recipes.md +86 -0
- package/skill/reference/styles.md +17 -10
- package/skill/reference/three-d.md +8 -7
- package/skill/reference/voice-sync.md +1 -1
- package/skill/tests/studio.test.ts +111 -0
- package/skill/types/index.d.ts +65 -0
- package/src/commands/assets.ts +5 -1
- package/src/contract/index.ts +1 -1
- package/src/hyperframes/Root.tsx +1 -0
- package/src/hyperframes/fonts.ts +54 -0
- package/src/hyperframes/frame.tsx +46 -0
- package/src/hyperframes/host.tsx +38 -0
- package/src/{remotion → hyperframes}/kit/Assemble3D.tsx +1 -1
- package/src/hyperframes/kit/BrandTransform3D.tsx +12 -0
- package/src/{remotion → hyperframes}/kit/BrowserFrame.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/Camera.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/Captions.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/Card3D.tsx +2 -2
- package/src/{remotion → hyperframes}/kit/Carry.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/ChapterFrame.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/ClipLayer.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/Counter.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/CounterRoll.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/Entrance.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/FootageLayer.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/GlassPanel.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/Grounds.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/Headline.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/Hero3D.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/HudOverlay.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/ImageLayers.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/KenBurnsImage.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/KeyedClip.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/Layers.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/LowerThird.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/Music.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/NamedCursor.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/Orbit3D.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/Particles3D.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/Place.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/PromptBox.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/Scene3D.tsx +2 -2
- package/src/{remotion → hyperframes}/kit/SceneFrame.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/ScreenOverlay.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/Sfx.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/SoundCues.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/TerminalLog.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/Text3D.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/TextOnImage.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/TitleCard.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/Voiceover.tsx +1 -1
- package/src/{remotion → hyperframes}/kit/Warp3D.tsx +1 -1
- package/src/hyperframes/kit/brand-transform.ts +25 -0
- package/src/{remotion → hyperframes}/kit/docs.ts +6 -2
- package/src/{remotion → hyperframes}/kit/index.ts +3 -0
- package/src/{remotion → hyperframes}/kit/sound-cues.ts +1 -1
- package/src/{remotion → hyperframes}/kit/sound-kinds.ts +14 -1
- package/src/{remotion → hyperframes}/kit/theme.ts +42 -40
- package/src/{remotion → hyperframes}/kit/ui-math.ts +1 -1
- package/src/hyperframes/math.ts +62 -0
- package/src/hyperframes/three.tsx +10 -0
- package/src/project/chromakey.ts +1 -1
- package/src/project/layers.ts +1 -1
- package/src/project/serve.ts +2 -2
- package/src/render/component-preview.ts +11 -55
- package/src/render/render.ts +62 -64
- package/src/render/serve.ts +31 -0
- package/src/render/static-check.ts +15 -4
- package/src/render/validate.ts +4 -4
- package/src/render/word-check.ts +1 -1
- package/src/render/worker.ts +71 -0
- package/src/testing/fixtures.ts +1 -1
- package/src/remotion/Root.tsx +0 -31
- /package/src/{remotion → hyperframes}/kit/Icon.tsx +0 -0
- /package/src/{remotion → hyperframes}/kit/beat.ts +0 -0
- /package/src/{remotion → hyperframes}/kit/bg-math.ts +0 -0
- /package/src/{remotion → hyperframes}/kit/brand-icons.ts +0 -0
- /package/src/{remotion → hyperframes}/kit/caption-groups.ts +0 -0
- /package/src/{remotion → hyperframes}/kit/caption-style.ts +0 -0
- /package/src/{remotion → hyperframes}/kit/image-layers-math.ts +0 -0
- /package/src/{remotion → hyperframes}/kit/inter-bold-typeface.ts +0 -0
- /package/src/{remotion → hyperframes}/kit/media.ts +0 -0
- /package/src/{remotion → hyperframes}/kit/motion-math.ts +0 -0
- /package/src/{remotion → hyperframes}/kit/music-math.ts +0 -0
- /package/src/{remotion → hyperframes}/kit/quiet-three.ts +0 -0
- /package/src/{remotion → hyperframes}/kit/sample-text.ts +0 -0
- /package/src/{remotion → hyperframes}/kit/scene3d-context.ts +0 -0
- /package/src/{remotion → hyperframes}/kit/seeded.ts +0 -0
- /package/src/{remotion → hyperframes}/kit/three-fx-math.ts +0 -0
- /package/src/{remotion → hyperframes}/kit/three-math.ts +0 -0
- /package/src/{remotion → hyperframes}/kit/transition-math.ts +0 -0
- /package/src/{remotion → hyperframes}/kit/ui-theme.ts +0 -0
- /package/src/{remotion → hyperframes}/kit/word-anchor.ts +0 -0
- /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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
-
|
|
23
|
-
-
|
|
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
|
|
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
|
|
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,
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 "
|
|
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 "
|
|
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 "
|
|
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
|
+
}
|
package/src/commands/assets.ts
CHANGED
|
@@ -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 "../
|
|
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}` : "";
|
package/src/contract/index.ts
CHANGED
|
@@ -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,
|
|
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;
|