blamcode 0.4.0__py3-none-any.whl
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.
- blamcode/__init__.py +9 -0
- blamcode/cli.py +122 -0
- blamcode/layer/README.md +43 -0
- blamcode/layer/config/agent/build.md +118 -0
- blamcode/layer/config/agent/debugger.md +32 -0
- blamcode/layer/config/agent/designer.md +31 -0
- blamcode/layer/config/agent/vision.md +26 -0
- blamcode/layer/config/agent/writer.md +28 -0
- blamcode/layer/config/command/ask.md +41 -0
- blamcode/layer/config/command/blam.md +24 -0
- blamcode/layer/config/command/explore.md +14 -0
- blamcode/layer/config/command/fix.md +14 -0
- blamcode/layer/config/command/open.md +18 -0
- blamcode/layer/config/command/review.md +14 -0
- blamcode/layer/config/opencode.json +53 -0
- blamcode/layer/config/themes/bangladeshi.json +67 -0
- blamcode/layer/config/themes/blamcode.json +217 -0
- blamcode/layer/config/tui.json +4 -0
- blamcode/layer/install.sh +752 -0
- blamcode/layer/scripts/__pycache__/patch-brand.cpython-312.pyc +0 -0
- blamcode/layer/scripts/blamcode +518 -0
- blamcode/layer/scripts/blamcode-browser +315 -0
- blamcode/layer/scripts/blamcode-menu +140 -0
- blamcode/layer/scripts/blamcode-uninstall +71 -0
- blamcode/layer/scripts/blamcode-vision +542 -0
- blamcode/layer/scripts/oc-settings.sh +138 -0
- blamcode/layer/scripts/patch-brand.py +267 -0
- blamcode/layer/skills/android-app/SKILL.md +53 -0
- blamcode/layer/skills/api-integration/SKILL.md +49 -0
- blamcode/layer/skills/bash-cli-expert/SKILL.md +48 -0
- blamcode/layer/skills/bot-development/SKILL.md +53 -0
- blamcode/layer/skills/clean-code-performance/SKILL.md +45 -0
- blamcode/layer/skills/database/SKILL.md +56 -0
- blamcode/layer/skills/debugging-fixes/SKILL.md +45 -0
- blamcode/layer/skills/deploy-hosting/SKILL.md +38 -0
- blamcode/layer/skills/docker/SKILL.md +74 -0
- blamcode/layer/skills/firebase-supabase/SKILL.md +61 -0
- blamcode/layer/skills/git-workflow/SKILL.md +63 -0
- blamcode/layer/skills/lets-scroll/SKILL.md +877 -0
- blamcode/layer/skills/lets-scroll/references/index-template.html +73 -0
- blamcode/layer/skills/lets-scroll/references/knockout.py +89 -0
- blamcode/layer/skills/lets-scroll/references/pipeline.md +312 -0
- blamcode/layer/skills/lets-scroll/references/prompts.md +194 -0
- blamcode/layer/skills/lets-scroll/references/scrub-engine.js +448 -0
- blamcode/layer/skills/project-structure/SKILL.md +74 -0
- blamcode/layer/skills/python-automation/SKILL.md +52 -0
- blamcode/layer/skills/react-next-best-practices/SKILL.md +54 -0
- blamcode/layer/skills/security-review/SKILL.md +48 -0
- blamcode/layer/skills/seo-basics/SKILL.md +44 -0
- blamcode/layer/skills/testing/SKILL.md +58 -0
- blamcode/layer/skills/ui-ux-responsive/SKILL.md +53 -0
- blamcode/layer/skills/website-builder/SKILL.md +47 -0
- blamcode-0.4.0.dist-info/METADATA +62 -0
- blamcode-0.4.0.dist-info/RECORD +58 -0
- blamcode-0.4.0.dist-info/WHEEL +5 -0
- blamcode-0.4.0.dist-info/entry_points.txt +2 -0
- blamcode-0.4.0.dist-info/licenses/LICENSE +21 -0
- blamcode-0.4.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
6
|
+
<title>BRAND — the world of SUBJECT</title>
|
|
7
|
+
<meta name="description" content="Scroll to fly through the world of BRAND." />
|
|
8
|
+
<style>
|
|
9
|
+
/* Theme the engine here. These match your generated scenes' background + palette. */
|
|
10
|
+
:root, .sw-root {
|
|
11
|
+
--sw-bg: #F5EDE0; /* == the scene background colour */
|
|
12
|
+
--sw-ink: #241d2b;
|
|
13
|
+
--sw-ink-soft: #6a6072;
|
|
14
|
+
--sw-accent: #9B7EBD; /* per-section accents override this at runtime */
|
|
15
|
+
}
|
|
16
|
+
</style>
|
|
17
|
+
</head>
|
|
18
|
+
<body>
|
|
19
|
+
<div id="top"></div>
|
|
20
|
+
<div id="world"></div>
|
|
21
|
+
|
|
22
|
+
<script src="scrub-engine.js"></script>
|
|
23
|
+
<script>
|
|
24
|
+
mountLetsScroll(document.getElementById('world'), {
|
|
25
|
+
brand: { name: 'BRAND', href: '#top' },
|
|
26
|
+
cta: { label: 'Order now', href: '#finale' },
|
|
27
|
+
hint: 'scroll to fly in',
|
|
28
|
+
diveScroll: 1.3,
|
|
29
|
+
connScroll: 0.9,
|
|
30
|
+
sections: [
|
|
31
|
+
// One object per scene, in order. `accent` colours the copy/route for that scene.
|
|
32
|
+
// First section is the hero (its copy greets on landing); last carries the CTA.
|
|
33
|
+
{
|
|
34
|
+
id: 'sceneA', label: 'Scene A',
|
|
35
|
+
still: 'assets/sceneA.webp',
|
|
36
|
+
clip: 'assets/vid/sceneA.mp4',
|
|
37
|
+
clipMobile: 'assets/vid/sceneA-m.mp4', // mobile opt-in only: lighter 720p encode served on phones
|
|
38
|
+
accent: '#8FB98A',
|
|
39
|
+
// scroll: 1.6, linger: 0.45, // optional pacing: longer dwell; camera settles mid-scene
|
|
40
|
+
eyebrow: 'Value prop label',
|
|
41
|
+
title: 'The hero line.',
|
|
42
|
+
body: 'One plain-spoken sentence about this stage.',
|
|
43
|
+
tags: ['Proof', 'Proof', 'Proof'],
|
|
44
|
+
},
|
|
45
|
+
// …middle scenes…
|
|
46
|
+
{
|
|
47
|
+
id: 'finale', label: 'The Product',
|
|
48
|
+
still: 'assets/product.webp',
|
|
49
|
+
clip: 'assets/vid/finale.mp4',
|
|
50
|
+
clipMobile: 'assets/vid/finale-m.mp4',
|
|
51
|
+
accent: '#9B7EBD',
|
|
52
|
+
eyebrow: 'And it all pours into',
|
|
53
|
+
title: 'One perfect thing.',
|
|
54
|
+
body: 'The payoff sentence.',
|
|
55
|
+
tags: [],
|
|
56
|
+
cta: { primary: { label: 'Get started', href: '#' },
|
|
57
|
+
secondary: { label: 'See more', href: '#' } },
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
// length === sections.length - 1, in order. Generated per SKILL.md Step 5.
|
|
61
|
+
connectors: [
|
|
62
|
+
'assets/vid/conn1.mp4',
|
|
63
|
+
// 'assets/vid/conn2.mp4', …
|
|
64
|
+
],
|
|
65
|
+
// Mobile opt-in only: lighter connectors for phones — same length/order as `connectors`.
|
|
66
|
+
connectorsMobile: [
|
|
67
|
+
'assets/vid/conn1-m.mp4',
|
|
68
|
+
// 'assets/vid/conn2-m.mp4', …
|
|
69
|
+
],
|
|
70
|
+
});
|
|
71
|
+
</script>
|
|
72
|
+
</body>
|
|
73
|
+
</html>
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Border-connected background knockout for diorama stills.
|
|
3
|
+
|
|
4
|
+
Removes the flat background of a scene image (leaving the diorama floating on
|
|
5
|
+
transparency) via a flood fill from the borders over pixels near the corner
|
|
6
|
+
colour. Interior regions that happen to match the background (e.g. cream walls
|
|
7
|
+
inside the scene) are preserved because the fill only reaches border-connected
|
|
8
|
+
pixels. The soft contact shadow is kept as a natural base.
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
python3 knockout.py scene1.png scene2.png ...
|
|
12
|
+
# writes scene1.rgba.png, scene2.rgba.png, ...
|
|
13
|
+
# optional: TOL env var (default 34) widens/narrows the bg match
|
|
14
|
+
|
|
15
|
+
Then encode to webp with alpha, e.g.:
|
|
16
|
+
cwebp -q 84 -alpha_q 95 -resize 1800 0 scene1.rgba.png -o scene1.webp
|
|
17
|
+
|
|
18
|
+
No numpy/ImageMagick needed — pure PIL. Pairs with SKILL.md Step 3.
|
|
19
|
+
"""
|
|
20
|
+
import os
|
|
21
|
+
import sys
|
|
22
|
+
from collections import deque
|
|
23
|
+
from PIL import Image, ImageFilter
|
|
24
|
+
|
|
25
|
+
TOL = float(os.environ.get("TOL", "34")) # RGB Euclidean distance counted as background
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def corner_color(im):
|
|
29
|
+
w, h = im.size
|
|
30
|
+
px = im.load()
|
|
31
|
+
pts = [(1, 1), (w - 2, 1), (1, h - 2), (w - 2, h - 2)]
|
|
32
|
+
r = sum(px[x, y][0] for x, y in pts) // 4
|
|
33
|
+
g = sum(px[x, y][1] for x, y in pts) // 4
|
|
34
|
+
b = sum(px[x, y][2] for x, y in pts) // 4
|
|
35
|
+
return (r, g, b)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def knock(inp, outp):
|
|
39
|
+
im = Image.open(inp).convert("RGB")
|
|
40
|
+
w, h = im.size
|
|
41
|
+
px = im.load()
|
|
42
|
+
cr, cg, cb = corner_color(im)
|
|
43
|
+
tol2 = TOL * TOL
|
|
44
|
+
|
|
45
|
+
def is_bg(x, y):
|
|
46
|
+
r, g, b = px[x, y]
|
|
47
|
+
dr, dg, db = r - cr, g - cg, b - cb
|
|
48
|
+
return dr * dr + dg * dg + db * db <= tol2
|
|
49
|
+
|
|
50
|
+
bg = bytearray(w * h)
|
|
51
|
+
seen = bytearray(w * h)
|
|
52
|
+
dq = deque()
|
|
53
|
+
for x in range(w):
|
|
54
|
+
for y in (0, h - 1):
|
|
55
|
+
i = y * w + x
|
|
56
|
+
if not seen[i] and is_bg(x, y):
|
|
57
|
+
seen[i] = 1; bg[i] = 1; dq.append((x, y))
|
|
58
|
+
for y in range(h):
|
|
59
|
+
for x in (0, w - 1):
|
|
60
|
+
i = y * w + x
|
|
61
|
+
if not seen[i] and is_bg(x, y):
|
|
62
|
+
seen[i] = 1; bg[i] = 1; dq.append((x, y))
|
|
63
|
+
while dq:
|
|
64
|
+
x, y = dq.popleft()
|
|
65
|
+
for nx, ny in ((x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)):
|
|
66
|
+
if 0 <= nx < w and 0 <= ny < h:
|
|
67
|
+
i = ny * w + nx
|
|
68
|
+
if not seen[i]:
|
|
69
|
+
seen[i] = 1
|
|
70
|
+
if is_bg(nx, ny):
|
|
71
|
+
bg[i] = 1; dq.append((nx, ny))
|
|
72
|
+
|
|
73
|
+
alpha = Image.new("L", (w, h), 255)
|
|
74
|
+
ap = alpha.load()
|
|
75
|
+
for y in range(h):
|
|
76
|
+
base = y * w
|
|
77
|
+
for x in range(w):
|
|
78
|
+
if bg[base + x]:
|
|
79
|
+
ap[x, y] = 0
|
|
80
|
+
alpha = alpha.filter(ImageFilter.GaussianBlur(1.4)) # soften the threshold contour
|
|
81
|
+
out = im.convert("RGBA")
|
|
82
|
+
out.putalpha(alpha)
|
|
83
|
+
out.save(outp)
|
|
84
|
+
print("knocked", outp)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
if __name__ == "__main__":
|
|
88
|
+
for name in sys.argv[1:]:
|
|
89
|
+
knock(name, name.rsplit(".", 1)[0] + ".rgba.png")
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
# Pipeline: copy-paste scripts (bash 3.2 safe)
|
|
2
|
+
|
|
3
|
+
Set these once. `NAMES` is the ordered section ids; the last is the hero/finale.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
WORK=/tmp/lets-scroll # scratch dir for prompts, sources, frames
|
|
7
|
+
ASSETS=./assets # where the site reads stills (webp) + clips (mp4)
|
|
8
|
+
mkdir -p "$WORK" "$ASSETS/vid"
|
|
9
|
+
NAMES="farm kitchen shop delivery plaza finale" # <-- your section ids, in order
|
|
10
|
+
|
|
11
|
+
# Chain video model — ONE for every chained clip (SKILL Step 4 roster).
|
|
12
|
+
# Must accept --start-image AND --end-image (verify: higgsfield model get <model>):
|
|
13
|
+
# seedance_2_0 | kling3_0 | seedance_2_0_mini (draft tier). Reference-only models can't
|
|
14
|
+
# hold a seam; models without --mode (e.g. kling3_0_turbo) need their own flag branch below.
|
|
15
|
+
# DEFAULT backend: Monid pay-per-clip (§7 — gen_dive_monid/gen_conn_monid with
|
|
16
|
+
# VRES=1080p|720p|480p instead of VOPTS). The gen_dive/gen_conn functions in §2/§4
|
|
17
|
+
# below are the Higgsfield-credits FALLBACK (and the only home of kling3_0/mini).
|
|
18
|
+
VMODEL=seedance_2_0
|
|
19
|
+
case "$VMODEL" in # per-model flags + durations (bash 3.2 safe)
|
|
20
|
+
kling3_0) VOPTS="--mode std --sound off"; DIVE_DUR=10; CONN_DUR=5 ;; # no --resolution param on Kling
|
|
21
|
+
seedance_2_0_mini) VOPTS="--mode std --resolution 720p"; DIVE_DUR=8; CONN_DUR=5 ;; # cheap frame-locked previz
|
|
22
|
+
*) VOPTS="--mode std --resolution 1080p"; DIVE_DUR=8; CONN_DUR=5 ;; # seedance_2_0 default
|
|
23
|
+
esac
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Higgsfield generations take minutes — every `higgsfield ... --wait` call below is meant
|
|
27
|
+
to run inside a **backgrounded** script. Launch the whole script with your tool's
|
|
28
|
+
background/detached mode and poll the progress log; never block the foreground.
|
|
29
|
+
|
|
30
|
+
**Manual asset path (SKILL Step 1.7):** none of the generate scripts here run — the
|
|
31
|
+
user renders from the prompt files and drops `still_<name>.png`, `dive_<name>.mp4`,
|
|
32
|
+
`conn_<i>.mp4` into `$WORK` themselves. Validate each drop (count, aspect, duration,
|
|
33
|
+
frame 0 matches the handed-over start frame), then §3 (frame extraction), §5/§6
|
|
34
|
+
(encode) and everything after run unchanged.
|
|
35
|
+
|
|
36
|
+
## 1. Scene stills (Step 2)
|
|
37
|
+
|
|
38
|
+
Write one prompt file per section to `$WORK/still_<name>.txt` (see prompts.md), then:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
gen_still() { # name
|
|
42
|
+
higgsfield generate create gpt_image_2 --prompt "$(cat "$WORK/still_$1.txt")" \
|
|
43
|
+
--aspect_ratio 3:2 --resolution 2k --quality high --wait --wait-timeout 15m --json \
|
|
44
|
+
> "$WORK/still_$1.json" 2> "$WORK/still_$1.err"
|
|
45
|
+
url=$(jq -r '.[0].result_url // empty' "$WORK/still_$1.json")
|
|
46
|
+
[ -n "$url" ] && curl -fsSL "$url" -o "$WORK/still_$1.png" && echo "still $1 ok" || echo "still $1 FAIL"
|
|
47
|
+
}
|
|
48
|
+
for n in $NAMES; do gen_still "$n" & done ; wait
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Codex variant (STILLS_SOURCE=codex, SKILL Step 1.8 — subscription-billed, zero
|
|
52
|
+
credits; ~1–3 min each, parallelize in small batches):
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
gen_still_codex() { # name (< /dev/null is REQUIRED for parallel calls — see SKILL Gotchas)
|
|
56
|
+
codex exec -C "$WORK" -s workspace-write --skip-git-repo-check \
|
|
57
|
+
'Use the image generation tool ($imagegen) to generate: '"$(cat "$WORK/still_$1.txt")"' Wide 3:2 landscape, high resolution. Save it as ./still_'"$1"'.png. Do not do anything else.' \
|
|
58
|
+
> "$WORK/still_$1.codex.log" 2>&1 < /dev/null
|
|
59
|
+
[ -f "$WORK/still_$1.png" ] && echo "still $1 ok (codex)" || echo "still $1 FAIL (see .codex.log)"
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Convert to webp for the site (and optionally run knockout.py first for transparency):
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
for n in $NAMES; do cwebp -quiet -q 84 -resize 1800 0 "$WORK/still_$n.png" -o "$ASSETS/$n.webp"; done
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Review the stills for cohesion before continuing. Re-roll any off-style one (optionally
|
|
70
|
+
add `--image "$WORK/still_<good>.png"` to lock style).
|
|
71
|
+
|
|
72
|
+
## 2. Dive-in clips (Step 4)
|
|
73
|
+
|
|
74
|
+
Prompt files at `$WORK/dive_<name>.txt`. Start image = the solid-bg still PNG.
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
gen_dive() { # name ($VOPTS is unquoted on purpose — word-split flags)
|
|
78
|
+
higgsfield generate create "$VMODEL" --prompt "$(cat "$WORK/dive_$1.txt")" \
|
|
79
|
+
--start-image "$WORK/still_$1.png" \
|
|
80
|
+
$VOPTS --aspect_ratio 16:9 --duration "$DIVE_DUR" \
|
|
81
|
+
--wait --wait-timeout 20m --json > "$WORK/dive_$1.json" 2> "$WORK/dive_$1.err"
|
|
82
|
+
url=$(jq -r '.[0].result_url // empty' "$WORK/dive_$1.json")
|
|
83
|
+
[ -n "$url" ] && curl -fsSL "$url" -o "$WORK/dive_$1.mp4" && echo "dive $1 ok" || echo "dive $1 FAIL"
|
|
84
|
+
}
|
|
85
|
+
for n in $NAMES; do gen_dive "$n" & done ; wait
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Re-roll individual failures (503 / credit race are transient):
|
|
89
|
+
`gen_dive shop` (just that one).
|
|
90
|
+
|
|
91
|
+
## 3. Extract boundary frames — the seam handoff (Step 5)
|
|
92
|
+
|
|
93
|
+
For each adjacent pair, the connector's start = dive_i's LAST frame, end = dive_{i+1}'s
|
|
94
|
+
FIRST frame — extracted from the **rendered videos**, never the stills.
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
set -- $NAMES
|
|
98
|
+
prev=""
|
|
99
|
+
for n in "$@"; do
|
|
100
|
+
ffmpeg -v error -ss 0 -i "$WORK/dive_$n.mp4" -frames:v 1 -q:v 2 "$WORK/first_$n.png" # establishing
|
|
101
|
+
ffmpeg -v error -sseof -0.15 -i "$WORK/dive_$n.mp4" -frames:v 1 -q:v 2 "$WORK/last_$n.png" # interior
|
|
102
|
+
done
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## 4. Connector clips (Step 5)
|
|
106
|
+
|
|
107
|
+
Prompt files at `$WORK/conn_<i>.txt` (i = 1..N-1). Iterate adjacent pairs:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
gen_conn() { # i startPng endPng (end-image required → seedance/kling3_0 only)
|
|
111
|
+
higgsfield generate create "$VMODEL" --prompt "$(cat "$WORK/conn_$1.txt")" \
|
|
112
|
+
--start-image "$2" --end-image "$3" \
|
|
113
|
+
$VOPTS --aspect_ratio 16:9 --duration "$CONN_DUR" \
|
|
114
|
+
--wait --wait-timeout 20m --json > "$WORK/conn_$1.json" 2> "$WORK/conn_$1.err"
|
|
115
|
+
url=$(jq -r '.[0].result_url // empty' "$WORK/conn_$1.json")
|
|
116
|
+
[ -n "$url" ] && curl -fsSL "$url" -o "$WORK/conn_$1.mp4" && echo "conn $1 ok" || echo "conn $1 FAIL"
|
|
117
|
+
}
|
|
118
|
+
set -- $NAMES ; i=0 ; prev=""
|
|
119
|
+
for n in "$@"; do
|
|
120
|
+
if [ -n "$prev" ]; then i=$((i+1)); gen_conn "$i" "$WORK/last_$prev.png" "$WORK/first_$n.png" & fi
|
|
121
|
+
prev="$n"
|
|
122
|
+
done ; wait
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## 5. Encode everything for scrubbing (Step 6)
|
|
126
|
+
|
|
127
|
+
Native resolution (1080p from seedance std; kling3_0 std returned **720p** in testing —
|
|
128
|
+
never upscale, encode what ffprobe reports), crf 20, GOP 8, light sharpen, no audio,
|
|
129
|
+
faststart. Same for dives + connectors.
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
enc() { ffmpeg -v error -y -i "$1" -an -vf "unsharp=5:5:0.8:5:5:0.0" \
|
|
133
|
+
-c:v libx264 -preset slow -crf 20 -pix_fmt yuv420p \
|
|
134
|
+
-g 8 -keyint_min 8 -sc_threshold 0 -movflags +faststart "$2"; echo "enc $2 $(du -h "$2"|cut -f1)"; }
|
|
135
|
+
|
|
136
|
+
for n in $NAMES; do enc "$WORK/dive_$n.mp4" "$ASSETS/vid/$n.mp4"; done
|
|
137
|
+
i=0; for f in "$WORK"/conn_*.mp4; do i=$((i+1)); enc "$f" "$ASSETS/vid/conn$i.mp4"; done
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Now the engine config's `sections[k].clip = assets/vid/<name>.mp4` and
|
|
141
|
+
`connectors = [assets/vid/conn1.mp4, …]` (length N-1, in order).
|
|
142
|
+
|
|
143
|
+
## 6. Centre-crop mobile encodes — FALLBACK ONLY, not the mobile version
|
|
144
|
+
|
|
145
|
+
**The mobile version is the native 9:16 portrait chain (§6b).** This section's crop
|
|
146
|
+
encodes exist for one case: the user opted into mobile but credits can't cover the
|
|
147
|
+
portrait chain — and shipping them must be called out and approved, never silent
|
|
148
|
+
(portrait phones will see the landscape film's centre ~26%). The encode mechanics
|
|
149
|
+
matter either way: scrubbing sets `currentTime` every frame, and a phone decoder's
|
|
150
|
+
**seek cost scales with how many frames it must decode from the nearest keyframe** — so
|
|
151
|
+
a 1080p `-g 8` master that scrubs fine on a laptop stutters on a phone. A **smaller
|
|
152
|
+
frame + tighter GOP** fixes that (and halves the bytes on cellular). The crop `-m.mp4`
|
|
153
|
+
sibling per clip:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# 720p, GOP 4 (twice the keyframes = ~half the seek-decode work), crf 23, same sharpen/faststart.
|
|
157
|
+
encm() { ffmpeg -v error -y -i "$1" -an -vf "scale=-2:720,unsharp=5:5:0.6:5:5:0.0" \
|
|
158
|
+
-c:v libx264 -preset slow -crf 23 -pix_fmt yuv420p \
|
|
159
|
+
-g 4 -keyint_min 4 -sc_threshold 0 -movflags +faststart "$2"; echo "encm $2 $(du -h "$2"|cut -f1)"; }
|
|
160
|
+
|
|
161
|
+
for n in $NAMES; do encm "$WORK/dive_$n.mp4" "$ASSETS/vid/$n-m.mp4"; done
|
|
162
|
+
i=0; for f in "$WORK"/conn_*.mp4; do i=$((i+1)); encm "$f" "$ASSETS/vid/conn$i-m.mp4"; done
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Wire the variants in the engine config — the engine serves them automatically on phones,
|
|
166
|
+
falling back to the desktop `clip` when a mobile one is absent:
|
|
167
|
+
|
|
168
|
+
```js
|
|
169
|
+
sections[k].clipMobile = 'assets/vid/<name>-m.mp4';
|
|
170
|
+
connectorsMobile = ['assets/vid/conn1-m.mp4', …]; // length N-1, in order
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
If phone scrubbing still stutters, tighten the GOP further (`-g 2`, or `-g 1` for all-intra
|
|
174
|
+
= instant seeks at the cost of larger files); if cellular weight is the bigger worry, raise
|
|
175
|
+
`crf` (24–26) or drop to `scale=-2:600`. If the master is already 720p (e.g. kling3_0 std),
|
|
176
|
+
the mobile encode still pays off — the tighter GOP is what makes phone seeks cheap. All-mobile encodes stay 16:9 — the engine
|
|
177
|
+
centre-crops them; see the portrait note in SKILL Step 8 / prompts.md.
|
|
178
|
+
|
|
179
|
+
## 6b. Native 9:16 portrait chain — THE mobile version (Step 1.6 opt-in)
|
|
180
|
+
|
|
181
|
+
When the user opts into mobile, this is what they get: a **parallel 9:16 chain** rendered
|
|
182
|
+
natively for phones and shipped as the mobile variants — never the §6 crops (those are the
|
|
183
|
+
no-credits stopgap). Same seam laws as the main chain — the portrait chain frame-locks
|
|
184
|
+
against its own rendered frames, never the landscape ones. Budget ~2N-1 video gens +
|
|
185
|
+
re-rolls (interiors trip the NSFW filter in portrait too); state the credit cost at the
|
|
186
|
+
Step 1.6 interview.
|
|
187
|
+
|
|
188
|
+
1. **Portrait start canvases.** Don't hand the video model a 3:2 still and hope: composite
|
|
189
|
+
each scene onto a 1080×1920 canvas in the page bg colour (island at ~94% width, visual
|
|
190
|
+
centre at ~45% height). The render then opens exactly on what the portrait poster shows.
|
|
191
|
+
For knocked-out stills, composite the RGBA over the bg colour first.
|
|
192
|
+
2. **Dives/legs**: same prompt templates with a portrait clause up front ("Vertical
|
|
193
|
+
portrait composition, the diorama centered with generous [bg] space above and below"),
|
|
194
|
+
`--aspect_ratio 9:16`, same model/params as the main chain. Review each last frame
|
|
195
|
+
before chaining, as ever.
|
|
196
|
+
3. **Connectors**: extract first/last frames **from the 9:16 renders** and generate 9:16
|
|
197
|
+
connectors between them. A native 9:16 scene mixed into cropped-16:9 neighbours pops at
|
|
198
|
+
both seams — the portrait chain must be complete, not partial.
|
|
199
|
+
4. **Encode** with the §6 settings but portrait-oriented scale: `scale=720:-2` (720 wide),
|
|
200
|
+
`-g 4`, crf 23 → these ARE the `-m.mp4` mobile files (and they replace any §6 crop
|
|
201
|
+
stopgaps that shipped earlier).
|
|
202
|
+
5. **Posters**: extract each 9:16 dive's first frame → webp → wire as the section's
|
|
203
|
+
`stillMobile` so the poster matches the portrait video's frame 0 (no landscape→portrait
|
|
204
|
+
flash when the clip paints). Engine support: `sections[k].stillMobile`.
|
|
205
|
+
|
|
206
|
+
## 7. Monid backend — Seedance 2.0 pay-per-clip (the DEFAULT; qualified 2026-07-25)
|
|
207
|
+
|
|
208
|
+
`bytedance /v1/video/seedance-2.0` via Monid is the roster's `seedance_2_0` billed
|
|
209
|
+
per clip in USD, and the **default** chain backend (SKILL Step 4 → Monid backend;
|
|
210
|
+
both probes passed) — use these functions in the §2/§4 loops unless the build fell
|
|
211
|
+
back to Higgsfield credits. Same chain laws as everywhere else — only the I/O
|
|
212
|
+
differs: **frames ride Monid's free `sfs` file
|
|
213
|
+
system** (inline base64 is rejected), **`ratio` must be explicit** (the adaptive
|
|
214
|
+
default follows the input image's aspect), and runs are fire-and-poll. Token-priced
|
|
215
|
+
`w×h×24×sec/1024` at $7/1M (480p/720p), $7.7/1M (1080p) — measured: 1080p ≈ $2.99
|
|
216
|
+
dive / $1.87 connector; 720p ≈ $1.21 / $0.76; 480p previz ≈ $0.28 / $0.35.
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
# helper: upload a local frame to sfs, print a signed public URL for it ($0).
|
|
220
|
+
# NB: /cat and /ls take the SAME relative path you gave /put — not the
|
|
221
|
+
# "home/..."-prefixed path /put echoes back (that one 404s).
|
|
222
|
+
monid_frame_url() { # localPng remoteName (JPEG-compresses on the way up)
|
|
223
|
+
jpg="$WORK/sfs_$2.jpg"
|
|
224
|
+
ffmpeg -v error -y -i "$1" -vf "scale='min(1536,iw)':-2" -q:v 2 "$jpg"
|
|
225
|
+
size=$(stat -f%z "$jpg")
|
|
226
|
+
up=$(NO_COLOR=1 monid run -p sfs -e /put \
|
|
227
|
+
-i "{\"path\":\"chain/$2.jpg\",\"sizeBytes\":$size,\"ttl\":\"1h\"}" -w 60 -j \
|
|
228
|
+
| jq -r '.output.uploadUrl')
|
|
229
|
+
curl -fsS -T "$jpg" "$up" > /dev/null
|
|
230
|
+
NO_COLOR=1 monid run -p sfs -e /cat -i "{\"path\":\"chain/$2.jpg\",\"ttl\":\"1d\"}" \
|
|
231
|
+
-w 60 -j | jq -r '.output.url'
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
# fire-and-poll (the CLI's -w caps at 120s and seedance can exceed it)
|
|
235
|
+
monid_wait() { # runId outJson
|
|
236
|
+
while :; do
|
|
237
|
+
NO_COLOR=1 monid runs get -r "$1" -j > "$2" 2>/dev/null
|
|
238
|
+
case "$(jq -r '.status // empty' "$2")" in
|
|
239
|
+
COMPLETED|FAILED|BLOCKED|STOPPED|TIME_OUT) break ;;
|
|
240
|
+
esac
|
|
241
|
+
sleep 8
|
|
242
|
+
done
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
gen_dive_monid() { # name (VRES=1080p|720p|480p; DIVE_DUR as usual)
|
|
246
|
+
furl=$(monid_frame_url "$WORK/still_$1.png" "still_$1")
|
|
247
|
+
jq -n --arg p "$(cat "$WORK/dive_$1.txt")" --arg u "$furl" --arg r "$VRES" \
|
|
248
|
+
'{content:[{type:"text",text:$p},
|
|
249
|
+
{type:"image_url",image_url:{url:$u},role:"first_frame"}],
|
|
250
|
+
resolution:$r, duration:'"$DIVE_DUR"', ratio:"16:9", generate_audio:false}' \
|
|
251
|
+
> "$WORK/dive_$1.body.json"
|
|
252
|
+
rid=$(NO_COLOR=1 monid run -p bytedance -e /v1/video/seedance-2.0 \
|
|
253
|
+
-f "$WORK/dive_$1.body.json" -j | jq -r '.runId')
|
|
254
|
+
monid_wait "$rid" "$WORK/dive_$1.json"
|
|
255
|
+
url=$(jq -r '.output.content.video_url // empty' "$WORK/dive_$1.json")
|
|
256
|
+
[ -n "$url" ] && curl -fsSL "$url" -o "$WORK/dive_$1.mp4" \
|
|
257
|
+
&& echo "dive $1 ok (\$$(jq -r '.cost.value' "$WORK/dive_$1.json"))" \
|
|
258
|
+
|| echo "dive $1 FAIL ($(jq -r '.status' "$WORK/dive_$1.json"))"
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
gen_conn_monid() { # i startPng endPng
|
|
262
|
+
su=$(monid_frame_url "$2" "conn$1_start"); eu=$(monid_frame_url "$3" "conn$1_end")
|
|
263
|
+
jq -n --arg p "$(cat "$WORK/conn_$1.txt")" --arg s "$su" --arg e "$eu" --arg r "$VRES" \
|
|
264
|
+
'{content:[{type:"text",text:$p},
|
|
265
|
+
{type:"image_url",image_url:{url:$s},role:"first_frame"},
|
|
266
|
+
{type:"image_url",image_url:{url:$e},role:"last_frame"}],
|
|
267
|
+
resolution:$r, duration:'"$CONN_DUR"', ratio:"16:9", generate_audio:false}' \
|
|
268
|
+
> "$WORK/conn_$1.body.json"
|
|
269
|
+
rid=$(NO_COLOR=1 monid run -p bytedance -e /v1/video/seedance-2.0 \
|
|
270
|
+
-f "$WORK/conn_$1.body.json" -j | jq -r '.runId')
|
|
271
|
+
monid_wait "$rid" "$WORK/conn_$1.json"
|
|
272
|
+
url=$(jq -r '.output.content.video_url // empty' "$WORK/conn_$1.json")
|
|
273
|
+
[ -n "$url" ] && curl -fsSL "$url" -o "$WORK/conn_$1.mp4" \
|
|
274
|
+
&& echo "conn $1 ok (\$$(jq -r '.cost.value' "$WORK/conn_$1.json"))" \
|
|
275
|
+
|| echo "conn $1 FAIL ($(jq -r '.status' "$WORK/conn_$1.json"))"
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Default usage in §2/§4: same loops, `gen_dive_monid`/`gen_conn_monid` in place of
|
|
280
|
+
the Higgsfield `gen_dive`/`gen_conn` (mobile chain: `ratio:"9:16"` and the §6b
|
|
281
|
+
portrait canvases). Previz: same functions with `VRES=480p`.
|
|
282
|
+
Result URLs expire (~24–48 h) — the functions download immediately. Read the billed
|
|
283
|
+
`cost.value` per clip (echoed in the ok-line) and `monid balance` between phases; a
|
|
284
|
+
`BLOCKED` status is a workspace budget/run cap — terminal, surface it to the user.
|
|
285
|
+
Frame extraction, encoding, QA: identical to the Higgsfield path.
|
|
286
|
+
|
|
287
|
+
**Qualification harness for future/changed endpoints** (each probe = one cheap 480p
|
|
288
|
+
clip): (1) prompt + first_frame from a real still → downloaded video's frame 0 must
|
|
289
|
+
match the still (eyeball + PSNR ≳ 30 dB) and `cost.value` must match the advertised
|
|
290
|
+
cell; (2) add a last_frame from a *different* still → the final frame must land on
|
|
291
|
+
that composition (Seedance-style near-miss ok — the crossfade covers it). Known
|
|
292
|
+
failure to watch for (it's why the harness exists): `minimax /v1/video_generation`
|
|
293
|
+
still silently drops the image when `prompt` is present — image-only output proves
|
|
294
|
+
nothing about steerability.
|
|
295
|
+
|
|
296
|
+
## Notes
|
|
297
|
+
|
|
298
|
+
- `.[0].result_url` is the field on the `--wait --json` job object. `.min_result_url` is
|
|
299
|
+
a lower-res preview if you ever want it.
|
|
300
|
+
- **NSFW fallback across models**: if one clip keeps getting flagged on seedance after
|
|
301
|
+
re-rolls + prompt scrubbing, regenerate just that clip on `kling3_0` with the SAME
|
|
302
|
+
start/end frames: `VMODEL=kling3_0; VOPTS="--mode std --sound off"; gen_conn 3 …` —
|
|
303
|
+
then restore your chain model. See SKILL Gotchas for the trade-off.
|
|
304
|
+
- **Previz on the cheap**: run the whole chain once with `VMODEL=seedance_2_0_mini`
|
|
305
|
+
(frame-locking intact, ~720p) to validate the journey and seams before spending
|
|
306
|
+
full-model credits — because it's still seamless, the previz translates directly to the
|
|
307
|
+
final render. Don't reach for reference-only models here: without `--start/--end-image`
|
|
308
|
+
they can't hold a seam, so their output can't be chained (Step 4 rule).
|
|
309
|
+
- If a whole batch stalls, check `higgsfield workspace list` for credits and
|
|
310
|
+
`$WORK/*.err` for the reason.
|
|
311
|
+
- Concurrency: launching ~5–6 gens at once is fine; much more can trigger transient
|
|
312
|
+
credit/race errors — stagger or re-roll.
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# Prompt templates & intake
|
|
2
|
+
|
|
3
|
+
Everything here is fill-in-the-slots. Keep the **style preamble** byte-for-byte identical
|
|
4
|
+
across all scene stills — that identical text is what makes the world feel like one place.
|
|
5
|
+
|
|
6
|
+
## Intake checklist (Step 1)
|
|
7
|
+
|
|
8
|
+
Collect and write down:
|
|
9
|
+
|
|
10
|
+
- `SUBJECT` — the business + one-line pitch.
|
|
11
|
+
- `BRAND_NAME` — display name.
|
|
12
|
+
- `PALETTE` — 4–6 named hexes, e.g. `taro #9B7EBD, cream #F5EDE0, caramel #C88A5A, matcha #8FB98A, plum #3A2E48`. Pick ONE as the scene **background** colour (usually the lightest) and one as the primary **accent**.
|
|
13
|
+
- `TONE` — a word or two (cozy/premium, playful, industrial…).
|
|
14
|
+
- `STYLE` — the art direction (default below).
|
|
15
|
+
- `SECTIONS[]` — ordered list; for each: `id`, `label`, `subject` (what's in the diorama), `eyebrow`, `title`, `body` (≤ 1 sentence), `tags[]` (0–3). Last section = hero product + CTA.
|
|
16
|
+
- `N` — scene count: 2 (teaser: opener + hero/CTA) | 4 (short journey) | 6 (full
|
|
17
|
+
film — **maximum**). **Always asked** (SKILL Step 1.5) before proposing the section
|
|
18
|
+
list. Assets = N stills + (2N−1) clips.
|
|
19
|
+
- `CAMERA` — fly-through (arch B: dives + aerial hops — the flagship-demo look) |
|
|
20
|
+
walkthrough (arch A: one continuous forward flight) | locked-iso (arch A + the
|
|
21
|
+
locked-iso clause below: one fixed angle for the whole film). **Always asked**
|
|
22
|
+
(SKILL Step 1.4), presented by feel with a one-line trade-off each.
|
|
23
|
+
- `MOBILE` — yes/no. **Always asked** (SKILL Step 1.6), presented to the user
|
|
24
|
+
with the ~2× credit cost stated. Yes = the **native 9:16 portrait chain**
|
|
25
|
+
(pipeline §6b): portrait renders of every dive/connector +
|
|
26
|
+
`clipMobile`/`connectorsMobile`/`stillMobile` wiring + the full mobile QA. The
|
|
27
|
+
§6 crop encodes are a no-credits stopgap only.
|
|
28
|
+
- `ASSET_SOURCE` — automatic (the skill renders: Higgsfield/Codex stills,
|
|
29
|
+
Monid/Higgsfield video) | manual (the skill writes every prompt file + the
|
|
30
|
+
conditioning frames; the user renders in tools of their choice and drops the
|
|
31
|
+
finished files into `$WORK`). **Always asked** (SKILL Step 1.7). On the manual
|
|
32
|
+
path `VIDEO_TIER`/`STILLS_SOURCE` below don't apply — but the user's video tool
|
|
33
|
+
must accept a start frame (and, for arch B connectors, an end frame).
|
|
34
|
+
- `VIDEO_TIER` — (automatic path only) default is `seedance_2_0` **via Monid**
|
|
35
|
+
(pay-per-clip; previz = same endpoint at 480p, final at 1080p).
|
|
36
|
+
Higgsfield-credit alternates: draft (`seedance_2_0_mini`) | standard
|
|
37
|
+
(`seedance_2_0`) | alternate (`kling3_0`). Chosen by cost at SKILL Step 1.8,
|
|
38
|
+
with the estimated total stated before anything renders.
|
|
39
|
+
- `STILLS_SOURCE` — (automatic path only) higgsfield (`gpt_image_2`, spends
|
|
40
|
+
credits) | codex (`image_gen`, subscription-billed; only offer when the Codex
|
|
41
|
+
CLI is present).
|
|
42
|
+
|
|
43
|
+
## Style preamble (default: clay diorama)
|
|
44
|
+
|
|
45
|
+
Reuse verbatim in every scene prompt. Swap the bracketed bits for the brand's palette/bg.
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
Isometric low-poly 3D diorama floating as a small rounded island on a plain solid
|
|
49
|
+
[BG_HEX] background with a soft contact shadow beneath it. Soft matte clay 3D render,
|
|
50
|
+
rounded toy-model shapes, gentle warm studio lighting, soft long shadows, tilt-shift
|
|
51
|
+
miniature look. Cohesive color palette of [PALETTE]. Highly detailed, centered
|
|
52
|
+
composition, absolutely no text, no letters, no numbers, no logos.
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Alternate directions (swap the first two sentences, keep the palette/no-text tail):
|
|
56
|
+
- **Flat papercraft:** "Isometric layered paper-craft diorama, matte cardstock, clean die-cut edges, subtle drop shadows between layers."
|
|
57
|
+
- **Glossy toy:** "Isometric glossy vinyl-toy diorama, smooth plastic shading, soft rim light, collectible figurine look."
|
|
58
|
+
- **Claymation:** "Isometric stop-motion clay set, visible thumbprints, handmade plasticine texture, soft studio softbox light."
|
|
59
|
+
- **Neon night:** "Isometric miniature at night, warm interior glow and neon signage, moody rim light, wet reflective ground."
|
|
60
|
+
- **Photoreal architectural** (real estate, hospitality, premium/luxury): "Ultra-photorealistic architectural photography of a single cohesive [subject], cinematic wide-angle, warm golden-hour light, natural materials, restrained designer furnishings, a breathtaking view, editorial magazine quality (Architectural Digest), shallow depth of field, no people." For photoreal, drop the floating-island framing and the knockout (Step 3) — the scenes are **full-bleed** (a dark page background reads premium), the "dive" glides *through doorways/glass* rather than opening a roof, and cohesion comes entirely from the identical preamble (do NOT pass an `--image` reference — it clones the same room). Interiors trip Seedance's NSFW filter often; see SKILL Gotchas.
|
|
61
|
+
|
|
62
|
+
## Scene still prompt (Step 2)
|
|
63
|
+
|
|
64
|
+
Every prompt must be **fully self-contained**: on the manual path each still may be
|
|
65
|
+
rendered in a different tool or session, so the aspect ratio, the background lock and
|
|
66
|
+
the palette must live IN THE PROMPT TEXT — never rely on tool-side settings you can't
|
|
67
|
+
guarantee, and never strip these lines when adapting the template.
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
[STYLE PREAMBLE]
|
|
71
|
+
Render a wide 3:2 landscape image, at least 1536 px wide. The background stays a plain
|
|
72
|
+
solid [BG_HEX] across the whole frame — a completely empty backdrop: no sky, no clouds,
|
|
73
|
+
no horizon, no gradient. Centered composition with a little headroom; the focal subject
|
|
74
|
+
horizontally centred and nothing essential at the far left/right edges. Absolutely no
|
|
75
|
+
text, no letters, no numbers, no logos.
|
|
76
|
+
Subject: [SECTION.subject — describe the miniature scene: the building/space, a few
|
|
77
|
+
characters doing the work, the props that signal this stage of the business].
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Tips:
|
|
81
|
+
- Name concrete props (they anchor the scene): tanks, cauldrons, conveyor, crates, awning, string lights, benches, scooters, map pins.
|
|
82
|
+
- For the final "hero product" section, drop the diorama-island framing and prompt a
|
|
83
|
+
single oversized product centerpiece floating on the same background with a few small
|
|
84
|
+
orbiting props.
|
|
85
|
+
- **Compose for the centre.** The page renders every clip `object-fit:cover`. Keep the
|
|
86
|
+
focal subject horizontally centred with a little headroom, and don't park anything
|
|
87
|
+
essential at the far left/right edges. Mobile ships its own native 9:16 chain
|
|
88
|
+
(pipeline §6b), so this is not about surviving a crop — but a centred composition makes
|
|
89
|
+
the portrait renders open cleanly from the same still, and it keeps the dive's focal
|
|
90
|
+
point where the camera actually flies.
|
|
91
|
+
- Automatic-path CLI flags: `--aspect_ratio 3:2 --resolution 2k --quality high`. The
|
|
92
|
+
prompt's own 3:2 + background-lock sentences still do the consistency work whenever a
|
|
93
|
+
still is rendered outside that CLI (manual path, another tool, a re-roll elsewhere).
|
|
94
|
+
|
|
95
|
+
## Leg prompt — architecture A, continuous forward take (Step 4)
|
|
96
|
+
|
|
97
|
+
`--start-image = previous leg's ACTUAL last frame` (leg 0: the first scene's still).
|
|
98
|
+
**No `--end-image`.** The bolded clauses are the motion-handoff contract — keep them
|
|
99
|
+
verbatim; the mid-leg move is where the expression goes.
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
Single continuous cinematic camera move, no cuts. **Continue the same slow, steady
|
|
103
|
+
forward glide.** [MID-LEG MOVE — optional, from the library below.] The camera moves
|
|
104
|
+
into [SCENE i] toward [FOCAL POINT]. **In the final second, settle back into a slow,
|
|
105
|
+
steady forward glide toward [the doorway / opening / direction of the next scene].**
|
|
106
|
+
[STYLE tail + PALETTE]. Smooth, graceful, slow motion, subtle parallax. No text, no captions.
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Mid-leg move library (pick by concept; omit for a plain glide)
|
|
110
|
+
|
|
111
|
+
Reversals are safe *inside* a leg (it's one continuous render) — only a seam may never
|
|
112
|
+
reverse. That's why "ease back out" is fine mid-leg.
|
|
113
|
+
|
|
114
|
+
**Locked-iso clause** (`CAMERA` = locked isometric glide — SKILL Step 1.4/Step 4):
|
|
115
|
+
skip this library entirely and put this clause, verbatim, in the mid-leg slot of
|
|
116
|
+
EVERY leg:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
The camera keeps exactly the same high isometric angle throughout — no rotation, no
|
|
120
|
+
orbit, no tilt. It only travels straight and level, the world sliding past beneath
|
|
121
|
+
the same view.
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Keep the handoff-contract clauses around it unchanged. When checking each leg's last
|
|
125
|
+
frame, also check the ANGLE hasn't drifted (Seedance rotates slightly on long legs) —
|
|
126
|
+
re-roll the leg if the view has turned.
|
|
127
|
+
|
|
128
|
+
- **Half-orbit** (product, luxury): "sweeping in a slow half-orbit around [the hero
|
|
129
|
+
object], keeping it centered, then continuing past it"
|
|
130
|
+
- **Crane-up reveal** (scale, atriums, campuses): "rising smoothly as the full scale of
|
|
131
|
+
[the space] reveals below"
|
|
132
|
+
- **Low lateral track** (production lines, counters, shelves): "tracking low and level
|
|
133
|
+
alongside [the line], foreground objects sliding past in parallax"
|
|
134
|
+
- **Push-in + ease back** (craft, detail): "pushing in close to [the craft moment] until
|
|
135
|
+
it nearly fills the frame, then easing gently back out"
|
|
136
|
+
- **Rise-and-swoop** (travel, outdoors): "climbing in a gentle arc over [the terrain],
|
|
137
|
+
then swooping down toward [the next focal point]"
|
|
138
|
+
|
|
139
|
+
After rendering each leg, **check its last frame** before generating the next: it should
|
|
140
|
+
read as a frame from a calm forward glide (no motion blur sideways, no half-finished
|
|
141
|
+
orbit). If it doesn't, re-roll this leg — a bad handoff frame poisons every leg after it.
|
|
142
|
+
|
|
143
|
+
## Dive-in clip prompt (Step 4)
|
|
144
|
+
|
|
145
|
+
`--start-image = the scene still` (solid-bg version).
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
Single continuous cinematic camera move, no cuts. Begin high and far, looking down at the
|
|
149
|
+
whole [SECTION.subject] from outside like a tiny model. The camera slowly glides forward
|
|
150
|
+
and descends toward it, sweeping in toward [FOCAL POINT — the counter/the cauldrons/the
|
|
151
|
+
people], as if flying inside. As the camera pushes in, the roof and upper structure
|
|
152
|
+
gently lift and open away to reveal the warm interior. The backdrop stays a plain solid
|
|
153
|
+
[BG_HEX] the whole time — completely empty, no sky, no clouds, no horizon, no ground.
|
|
154
|
+
[STYLE tail: soft matte clay diorama, tilt-shift miniature, warm light, [PALETTE]].
|
|
155
|
+
Smooth, graceful, slow motion, subtle parallax. No text, no captions.
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
For scenes with no building to open (a field, a plaza, a road), replace the roof clause
|
|
159
|
+
with "the camera flies low across [the scene] toward [focal point]."
|
|
160
|
+
|
|
161
|
+
Params by chain model (SKILL Step 4 table): seedance —
|
|
162
|
+
`--mode std --resolution 1080p --aspect_ratio 16:9 --duration 8`, no audio flag;
|
|
163
|
+
kling3_0 — `--mode std --sound off --aspect_ratio 16:9 --duration 10` (no `--resolution`
|
|
164
|
+
param). Same for architecture-A legs.
|
|
165
|
+
|
|
166
|
+
## Connector clip prompt (Step 5)
|
|
167
|
+
|
|
168
|
+
`--start-image = dive_i LAST frame` (extracted), `--end-image = dive_{i+1} FIRST frame`
|
|
169
|
+
(extracted). Both from the RENDERED videos, not the stills.
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
Single continuous cinematic camera move, no cuts. The camera smoothly pulls up and back
|
|
173
|
+
out of [SCENE i], rising into the sky, then glides forward across the connected miniature
|
|
174
|
+
world and arrives above [SCENE i+1], beginning to descend toward it. One connected
|
|
175
|
+
miniature clay world floating in a plain solid [BG_HEX] void — empty backdrop, no sky,
|
|
176
|
+
no clouds — seamless flowing aerial transition. [STYLE tail + PALETTE]. Smooth
|
|
177
|
+
graceful slow motion. No text, no captions.
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
For the last connector into a hero-product finale: "…glides forward and the world
|
|
181
|
+
dissolves toward a single giant [PRODUCT] floating in soft [BG] space, arriving in front
|
|
182
|
+
of it."
|
|
183
|
+
|
|
184
|
+
seedance: `--mode std --resolution 1080p --aspect_ratio 16:9 --duration 5`; kling3_0:
|
|
185
|
+
`--mode std --sound off --aspect_ratio 16:9 --duration 5`. Connectors need `--end-image`
|
|
186
|
+
→ use a roster model that accepts it (Step 4).
|
|
187
|
+
|
|
188
|
+
## Copy per section (for the engine config)
|
|
189
|
+
|
|
190
|
+
- `eyebrow` — 2–4 words, uppercase feel (a value-prop label).
|
|
191
|
+
- `title` — 3–6 words, the beat's headline. First section = the site's hero line; last =
|
|
192
|
+
the payoff + it carries the CTA.
|
|
193
|
+
- `body` — one sentence, plain-spoken, from the visitor's side.
|
|
194
|
+
- `tags` — 0–3 short proof chips (e.g. "Fresh-cooked", "30-min delivery").
|