← back to Wallpaper Paint Antics
Rename wallpaper character to Wallo in all three videos
22cd4e4db3db2e937d97f2d0fb2ab5337d5eaa67 · 2026-09-05 00:00:41 -0700 · Steve Abrams
Files touched
M BRIEF.mdM DESIGN.mdM README.mdM STORYBOARD.mdM animation.jsR100 assets/wally.png assets/wallo.pngM episodes/01-runaway-roll.htmlM episodes/02-splash-of-personality.htmlM episodes/03-great-wall-off.htmlM index.htmlM scripts/build.mjsM scripts/mcp-proof.mjsM scripts/production.cjsM snapshots/frame-00-at-1.1s.pngM snapshots/frame-01-at-5.6s.pngM snapshots/frame-02-at-10.0s.pngM snapshots/frame-03-at-14.4s.pngM snapshots/frame-04-at-18.9s.pngM verification/01-runaway-roll-1.pngM verification/01-runaway-roll-12.8.pngM verification/01-runaway-roll-16.pngM verification/01-runaway-roll-19.pngM verification/01-runaway-roll-5.5.pngM verification/01-runaway-roll-8.pngM verification/01-runaway-roll-audio.txtM verification/01-runaway-roll-framemd5.txtM verification/01-runaway-roll-mp4-1.pngM verification/01-runaway-roll-mp4-13.pngM verification/01-runaway-roll-mp4-19.pngM verification/01-runaway-roll-mp4-8.pngM verification/01-runaway-roll-render.txtM verification/02-splash-of-personality-1.pngM verification/02-splash-of-personality-12.8.pngM verification/02-splash-of-personality-16.pngM verification/02-splash-of-personality-19.pngM verification/02-splash-of-personality-5.5.pngM verification/02-splash-of-personality-8.pngM verification/02-splash-of-personality-audio.txtM verification/02-splash-of-personality-framemd5.txtM verification/02-splash-of-personality-mp4-1.pngM verification/02-splash-of-personality-mp4-13.pngM verification/02-splash-of-personality-mp4-19.pngM verification/02-splash-of-personality-mp4-8.pngM verification/02-splash-of-personality-render.txtM verification/03-great-wall-off-1.pngM verification/03-great-wall-off-12.8.pngM verification/03-great-wall-off-16.pngM verification/03-great-wall-off-19.pngM verification/03-great-wall-off-5.5.pngM verification/03-great-wall-off-8.pngM verification/03-great-wall-off-audio.txtM verification/03-great-wall-off-framemd5.txtM verification/03-great-wall-off-mp4-1.pngM verification/03-great-wall-off-mp4-13.pngM verification/03-great-wall-off-mp4-19.pngM verification/03-great-wall-off-mp4-8.pngM verification/03-great-wall-off-render.txtM verification/contact-sheet.pngM verification/e2e-proof.jsonM verification/encoded-media-evidence.jsonM verification/mcp-gallery.pngM verification/mcp-proof.jsonM verification/mcp-stderr.txtR100 verification/mcp-wally-export.json verification/mcp-wallo-export.jsonM verification/preview-evidence.jsonA verification/rename-baseline.jsonM verification/verify-evidence.jsonM watch.html
Diff
commit 22cd4e4db3db2e937d97f2d0fb2ab5337d5eaa67
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sat Sep 5 00:00:41 2026 -0700
Rename wallpaper character to Wallo in all three videos
---
BRIEF.md | 2 +-
DESIGN.md | 6 +-
README.md | 2 +-
STORYBOARD.md | 16 +--
animation.js | 48 +++----
assets/{wally.png => wallo.png} | Bin
episodes/01-runaway-roll.html | 50 +++----
episodes/02-splash-of-personality.html | 50 +++----
episodes/03-great-wall-off.html | 50 +++----
index.html | 50 +++----
scripts/build.mjs | 4 +-
scripts/mcp-proof.mjs | 6 +-
scripts/production.cjs | 8 +-
snapshots/frame-00-at-1.1s.png | Bin 160450 -> 160585 bytes
snapshots/frame-01-at-5.6s.png | Bin 164284 -> 164445 bytes
snapshots/frame-02-at-10.0s.png | Bin 168749 -> 168892 bytes
snapshots/frame-03-at-14.4s.png | Bin 163197 -> 163334 bytes
snapshots/frame-04-at-18.9s.png | Bin 176927 -> 177161 bytes
verification/01-runaway-roll-1.png | Bin 160489 -> 160635 bytes
verification/01-runaway-roll-12.8.png | Bin 167174 -> 167308 bytes
verification/01-runaway-roll-16.png | Bin 162458 -> 162588 bytes
verification/01-runaway-roll-19.png | Bin 177240 -> 177469 bytes
verification/01-runaway-roll-5.5.png | Bin 164764 -> 164904 bytes
verification/01-runaway-roll-8.png | Bin 159519 -> 159656 bytes
verification/01-runaway-roll-audio.txt | 28 ++--
verification/01-runaway-roll-framemd5.txt | 40 +++---
verification/01-runaway-roll-mp4-1.png | Bin 95670 -> 95757 bytes
verification/01-runaway-roll-mp4-13.png | Bin 108387 -> 108706 bytes
verification/01-runaway-roll-mp4-19.png | Bin 120960 -> 120932 bytes
verification/01-runaway-roll-mp4-8.png | Bin 93259 -> 93091 bytes
verification/01-runaway-roll-render.txt | 91 ++++++------
verification/02-splash-of-personality-1.png | Bin 171562 -> 171700 bytes
verification/02-splash-of-personality-12.8.png | Bin 176445 -> 176579 bytes
verification/02-splash-of-personality-16.png | Bin 175353 -> 175490 bytes
verification/02-splash-of-personality-19.png | Bin 187568 -> 187810 bytes
verification/02-splash-of-personality-5.5.png | Bin 181253 -> 181382 bytes
verification/02-splash-of-personality-8.png | Bin 188228 -> 188363 bytes
verification/02-splash-of-personality-audio.txt | 34 ++---
verification/02-splash-of-personality-framemd5.txt | 40 +++---
verification/02-splash-of-personality-mp4-1.png | Bin 117046 -> 116747 bytes
verification/02-splash-of-personality-mp4-13.png | Bin 117836 -> 117867 bytes
verification/02-splash-of-personality-mp4-19.png | Bin 126327 -> 126498 bytes
verification/02-splash-of-personality-mp4-8.png | Bin 125126 -> 125095 bytes
verification/02-splash-of-personality-render.txt | 90 ++++++------
verification/03-great-wall-off-1.png | Bin 163932 -> 164088 bytes
verification/03-great-wall-off-12.8.png | Bin 177135 -> 177267 bytes
verification/03-great-wall-off-16.png | Bin 169225 -> 169365 bytes
verification/03-great-wall-off-19.png | Bin 166428 -> 166676 bytes
verification/03-great-wall-off-5.5.png | Bin 169212 -> 169350 bytes
verification/03-great-wall-off-8.png | Bin 172016 -> 172160 bytes
verification/03-great-wall-off-audio.txt | 38 ++---
verification/03-great-wall-off-framemd5.txt | 40 +++---
verification/03-great-wall-off-mp4-1.png | Bin 100452 -> 99933 bytes
verification/03-great-wall-off-mp4-13.png | Bin 126388 -> 126177 bytes
verification/03-great-wall-off-mp4-19.png | Bin 123043 -> 123165 bytes
verification/03-great-wall-off-mp4-8.png | Bin 117876 -> 117422 bytes
verification/03-great-wall-off-render.txt | 84 +++++------
verification/contact-sheet.png | Bin 602101 -> 602070 bytes
verification/e2e-proof.json | 157 ++++++++++-----------
verification/encoded-media-evidence.json | 58 ++++----
verification/mcp-gallery.png | Bin 591039 -> 590372 bytes
verification/mcp-proof.json | 16 +--
verification/mcp-stderr.txt | 2 +-
...mcp-wally-export.json => mcp-wallo-export.json} | 0
verification/preview-evidence.json | 38 ++---
verification/rename-baseline.json | 13 ++
verification/verify-evidence.json | 17 ++-
watch.html | 2 +-
68 files changed, 550 insertions(+), 530 deletions(-)
diff --git a/BRIEF.md b/BRIEF.md
index d62fa3a..ddeb28b 100644
--- a/BRIEF.md
+++ b/BRIEF.md
@@ -10,7 +10,7 @@ length: Three shorts, exactly 20 seconds each
User: "CReate 2 animated characsters using our mcp collection 2 People, 1 wallpaper 2. paint Wallpaper and 3 20 second videos of their antics"
-Deliver two original human cartoon characters: Wally, a meticulous wallpaper installer in teal overalls and a mustard cap; Pippa, a fearless painter with curly auburn hair, a coral shirt and cream dungarees. Both recur in all three shorts with articulated arms, legs, facial reactions and physical prop interactions.
+Deliver two original human cartoon characters: Wallo, a meticulous wallpaper installer in teal overalls and a mustard cap; Pippa, a fearless painter with curly auburn hair, a coral shirt and cream dungarees. Both recur in all three shorts with articulated arms, legs, facial reactions and physical prop interactions.
Inferred creative defaults: playful 2D cartoon animation, original instrumental music and comic sound effects, no spoken dialogue; portrait format follows personal media preference. User asked for finished videos; local rendering is authorized by that request. No publishing or paid provider setup.
diff --git a/DESIGN.md b/DESIGN.md
index 349cf15..99d7ca3 100644
--- a/DESIGN.md
+++ b/DESIGN.md
@@ -1,11 +1,11 @@
-# Wally & Pippa
+# Wallo & Pippa
Concept: an affectionate decorating double act in a warm, theatrical room, with an orderly wallpaper pattern colliding with irrepressible paint.
-Original code-native 2D character rigs, rounded silhouettes, navy outlines, tactile highlights and shadows. Wally has a round nose, a dark moustache, teal overalls, cream shirt, mustard cap and brown boots. Pippa has a curly auburn bun, freckles, coral sleeves, cream overalls and blue shoes. Shared proportions and unchanging costume geometry across episodes. Expressions change through eyelids, brows and mouths.
+Original code-native 2D character rigs, rounded silhouettes, navy outlines, tactile highlights and shadows. Wallo has a round nose, a dark moustache, teal overalls, cream shirt, mustard cap and brown boots. Pippa has a curly auburn bun, freckles, coral sleeves, cream overalls and blue shoes. Shared proportions and unchanging costume geometry across episodes. Expressions change through eyelids, brows and mouths.
Palette: background #f4eadb, ink #243b42, teal #267e7c, coral #e97556, mustard #e9b64b, paper #fff7e8. Warm wall with molding; patterned hanging paper, paint bucket, step ladder and shadowed floor establish the worksite.
-Type: Archivo Black for episode titles, Space Mono for episode labels, both embedded locally. Focal elements: the two large characters and the moving prop. Header anchors: WALLY & PIPPA and episode title. Bottom anchor: a short punchline timed to the payoff. Avoid UI boxes inside the films.
+Type: Archivo Black for episode titles, Space Mono for episode labels, both embedded locally. Focal elements: the two large characters and the moving prop. Header anchors: WALLO & PIPPA and episode title. Bottom anchor: a short punchline timed to the payoff. Avoid UI boxes inside the films.
Motion recipes: finite paused GSAP timeline; continuous deterministic character drawing driven by timeline time; anticipation, follow-through and squash at prop impacts. Particle-burst recipe supplies time-derived paint droplets; spring-pop entrance supplies playful punchline arrival. No generated still-image panning.
diff --git a/README.md b/README.md
index 5eb40f3..fefe5ef 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Wally & Pippa
+# Wallo & Pippa
Two original animated human decorators and three finished 20-second comedy shorts.
diff --git a/STORYBOARD.md b/STORYBOARD.md
index 0007ed0..2ae4d9d 100644
--- a/STORYBOARD.md
+++ b/STORYBOARD.md
@@ -1,19 +1,19 @@
# Three 20-second shorts
## 01 — The runaway roll
-0–3: Wally proudly holds a wallpaper roll. Pippa gives an enthusiastic thumbs-up.
-3–6: The roll slips, bouncing into the room; Wally spots it a beat too late.
-6–11: Wally chases. Pippa tries to stop it with her foot, and the roll ricochets.
+0–3: Wallo proudly holds a wallpaper roll. Pippa gives an enthusiastic thumbs-up.
+3–6: The roll slips, bouncing into the room; Wallo spots it a beat too late.
+6–11: Wallo chases. Pippa tries to stop it with her foot, and the roll ricochets.
11–15: Wallpaper winds around both decorators as they spin in a comic tangle.
15–18: A shared tug lifts the paper onto the wall; they pop free.
18–20: They pose beside the neat wallpaper. Punchline: THAT'S A WRAP.
## 02 — A splash of personality
-0–4: Pippa paints a broad coral swath. Wally carefully measures his wallpaper.
+0–4: Pippa paints a broad coral swath. Wallo carefully measures his wallpaper.
4–7: Pippa winds up an overconfident roller flourish.
-7–10: A stream of paint arcs toward Wally. He ducks; the wall gets a giant splat.
-10–13: Wally rises with one coral moustache. Pippa tries to look innocent.
-13–17: Wally adds wallpaper eyes to the splat, making a playful wall face.
+7–10: A stream of paint arcs toward Wallo. He ducks; the wall gets a giant splat.
+10–13: Wallo rises with one coral moustache. Pippa tries to look innocent.
+13–17: Wallo adds wallpaper eyes to the splat, making a playful wall face.
17–20: They laugh and point to their accidental art. Punchline: HAPPY ACCIDENT.
## 03 — The great wall-off
@@ -21,4 +21,4 @@
3–10: Furious wallpapering and painting race; sleeves and knees pump.
10–13: Both finish and boast. The seam between their sides looks awkward.
13–17: They exchange tools, work together, and finish a paper-and-paint feature wall.
-17–20: High-five, a small comic paint fingerprint on Wally's cap. Punchline: BETTER TOGETHER.
+17–20: High-five, a small comic paint fingerprint on Wallo's cap. Punchline: BETTER TOGETHER.
diff --git a/animation.js b/animation.js
index 127dbf8..b04573e 100644
--- a/animation.js
+++ b/animation.js
@@ -1,4 +1,4 @@
-/* Original Wally & Pippa character rigs. Every pose is a pure function of time. */
+/* Original Wallo & Pippa character rigs. Every pose is a pure function of time. */
(() => {
'use strict';
const canvas = document.getElementById('stage');
@@ -43,7 +43,7 @@
ellipse(152,1580,90,17,'#b39573');roll(142,1555,-.10,.75);
// Gentle sun shapes, a physical room light rather than a decorative UI effect.
c.save();c.globalAlpha=.18;path(q=>{q.moveTo(76,436);q.lineTo(278,436);q.lineTo(801,1507);q.lineTo(599,1507);q.closePath();},'#fffef0',null);c.restore();
- text('WALLY & PIPPA',65,100,37,TEAL,'Space Mono','left');
+ text('WALLO & PIPPA',65,100,37,TEAL,'Space Mono','left');
text(`SHORT 0${ep+1}`,1014,100,27,INK,'Space Mono','right');
const title=titles[ep];text(title,540,211,ep===1?59:72);
text('TWO DECORATORS. ONE BEAUTIFUL MESS.',540,292,24,INK,'Space Mono');
@@ -62,7 +62,7 @@
return [hx,hy];
}
function character(kind,x,y,t,pose={}){
- const wally=kind==='wally',skin=wally?'#e9ae82':'#f0ba97',shirt=wally?PAPER:CORAL,cloth=wally?TEAL:'#eee7d5';
+ const wallo=kind==='wallo',skin=wallo?'#e9ae82':'#f0ba97',shirt=wallo?PAPER:CORAL,cloth=wallo?TEAL:'#eee7d5';
const gait=pose.run||0,cycle=t*(pose.fast?19:13),kick=pose.kick||0;
const hop=gait*Math.abs(Math.sin(cycle))*19+(pose.hop||0);
const lean=pose.lean||0,scale=pose.scale||1.05,duck=pose.duck||0;
@@ -75,8 +75,8 @@
if(side===-1&&kick){kx-=kick*53;ky-=kick*31;fx-=kick*117;fy-=kick*110;}
path(q=>{q.moveTo(hx,hy);q.lineTo(kx,ky);q.lineTo(fx,fy);},null,INK,54);
path(q=>{q.moveTo(hx,hy);q.lineTo(kx,ky);q.lineTo(fx,fy);},null,cloth,44);
- line(kx+side*10,ky-16,fx+side*10,fy-12,wally?'#419995':'#fff8eb',7);
- group(fx,fy,.06*stride,()=>{rr(-24,-21,72,40,14,wally?'#895b41':'#457889',INK,5);line(-17,11,42,11,INK,7);line(-8,-12,18,-10,wally?'#d4a171':'#91b4be',4);});
+ line(kx+side*10,ky-16,fx+side*10,fy-12,wallo?'#419995':'#fff8eb',7);
+ group(fx,fy,.06*stride,()=>{rr(-24,-21,72,40,14,wallo?'#895b41':'#457889',INK,5);line(-17,11,42,11,INK,7);line(-8,-12,18,-10,wallo?'#d4a171':'#91b4be',4);});
}
const breath=Math.sin(t*3.1)*2.5;
group(0,-duck*0+breath,0,()=>{
@@ -86,33 +86,33 @@
path(q=>{q.moveTo(-58,-390);q.quadraticCurveTo(-91,-375,-82,-319);q.lineTo(-72,-196);q.quadraticCurveTo(0,-166,72,-196);q.lineTo(82,-319);q.quadraticCurveTo(90,-375,57,-390);q.closePath();},shirt,INK,6);
rr(-69,-308,138,139,25,cloth,INK,5);
line(-48,-378,-41,-280,cloth,26);line(48,-378,41,-280,cloth,26);
- for(const s of [-1,1]){ellipse(s*43,-315,7,7,GOLD,INK,3);line(s*42,-369,s*39,-334,wally?'#74b5a8':'#fff9ed',5);}
- rr(-36,-286,72,65,8,wally?'#206b6d':'#dad5c3',INK,4);path(q=>{q.moveTo(-27,-269);q.quadraticCurveTo(0,-239,27,-269);},null,wally?'#71aca0':'#fff8e9',4);
- if(wally){rr(-81,-224,27,60,4,'#b2774d',INK,3);rr(-74,-234,11,41,3,GOLD,INK,2);}else{ellipse(40,-199,10,7,CORAL);ellipse(-26,-234,7,10,TEAL);}
+ for(const s of [-1,1]){ellipse(s*43,-315,7,7,GOLD,INK,3);line(s*42,-369,s*39,-334,wallo?'#74b5a8':'#fff9ed',5);}
+ rr(-36,-286,72,65,8,wallo?'#206b6d':'#dad5c3',INK,4);path(q=>{q.moveTo(-27,-269);q.quadraticCurveTo(0,-239,27,-269);},null,wallo?'#71aca0':'#fff8e9',4);
+ if(wallo){rr(-81,-224,27,60,4,'#b2774d',INK,3);rr(-74,-234,11,41,3,GOLD,INK,2);}else{ellipse(40,-199,10,7,CORAL);ellipse(-26,-234,7,10,TEAL);}
rr(-24,-423,48,55,14,skin,INK,5);
// Hair mass and face with a broad, readable silhouette.
group(pose.headX||0,-500+(pose.headY||0),pose.headTilt||0,()=>{
- if(!wally){ellipse(-2,-34,96,101,'#8b503b',INK,6);ellipse(54,-108,43,43,'#8b503b',INK,5);for(let i=0;i<5;i++)ellipse(36+i*11,-119+(i%2)*13,18,22,i%2?'#a96848':'#8b503b');}
+ if(!wallo){ellipse(-2,-34,96,101,'#8b503b',INK,6);ellipse(54,-108,43,43,'#8b503b',INK,5);for(let i=0;i<5;i++)ellipse(36+i*11,-119+(i%2)*13,18,22,i%2?'#a96848':'#8b503b');}
ellipse(-81,6,18,27,skin,INK,4);ellipse(81,6,18,27,skin,INK,4);
path(q=>{q.moveTo(-74,-44);q.bezierCurveTo(-72,-104,72,-104,75,-41);q.lineTo(74,38);q.bezierCurveTo(69,99,-66,99,-74,37);q.closePath();},skin,INK,6);
ellipse(-58,28,14,8,'#d99074');ellipse(58,28,14,8,'#d99074');
- if(wally){path(q=>{q.moveTo(-78,-37);q.lineTo(-71,-69);q.lineTo(-62,-65);q.lineTo(-62,-31);},'#59483e',null);path(q=>{q.moveTo(62,-68);q.lineTo(78,-46);q.lineTo(74,-24);q.lineTo(62,-31);},'#59483e',null);}
+ if(wallo){path(q=>{q.moveTo(-78,-37);q.lineTo(-71,-69);q.lineTo(-62,-65);q.lineTo(-62,-31);},'#59483e',null);path(q=>{q.moveTo(62,-68);q.lineTo(78,-46);q.lineTo(74,-24);q.lineTo(62,-31);},'#59483e',null);}
else{for(let i=0;i<7;i++)ellipse(-66+i*21,-57-Math.sin(i*.6)*17,21,27,i%2?'#9f6042':'#8b503b',INK,3);}
- const blinking=((t+(wally?0:1.4))%4.1<.13),surprise=pose.expr==='shock',happy=pose.expr==='laugh';
- const look=pose.look??(wally?1:-1);
+ const blinking=((t+(wallo?0:1.4))%4.1<.13),surprise=pose.expr==='shock',happy=pose.expr==='laugh';
+ const look=pose.look??(wallo?1:-1);
for(const s of [-1,1]){
const ex=s*32,ey=-7;
if(blinking||happy){path(q=>{q.moveTo(ex-13,ey+4);q.quadraticCurveTo(ex,ey-10,ex+13,ey+4);},null,INK,5);}
else{ellipse(ex,ey,17,surprise?25:20,'#fffaf1',INK,3);ellipse(ex+look*4,ey+(surprise?2:0),6,10,INK);ellipse(ex+look*4+2,ey-5,2,3,PAPER);}
- const b=surprise?-49:-38;line(ex-12,b+s*(pose.expr==='suspicious'?7:0),ex+12,b+(!wally?3:0),INK,6);
+ const b=surprise?-49:-38;line(ex-12,b+s*(pose.expr==='suspicious'?7:0),ex+12,b+(!wallo?3:0),INK,6);
}
- ellipse(2,17,wally?19:12,wally?18:12,wally?'#de986f':'#eaa887',INK,3);
- if(wally){path(q=>{q.moveTo(0,38);q.bezierCurveTo(-14,25,-26,39,-41,36);q.bezierCurveTo(-33,65,-10,62,0,48);q.bezierCurveTo(13,64,39,57,43,37);q.bezierCurveTo(25,43,16,25,0,38);},pose.paint?CORAL:'#55423a',INK,3);}
- if(surprise){ellipse(0,wally?68:51,11,15,'#763e35',INK,3);}
+ ellipse(2,17,wallo?19:12,wallo?18:12,wallo?'#de986f':'#eaa887',INK,3);
+ if(wallo){path(q=>{q.moveTo(0,38);q.bezierCurveTo(-14,25,-26,39,-41,36);q.bezierCurveTo(-33,65,-10,62,0,48);q.bezierCurveTo(13,64,39,57,43,37);q.bezierCurveTo(25,43,16,25,0,38);},pose.paint?CORAL:'#55423a',INK,3);}
+ if(surprise){ellipse(0,wallo?68:51,11,15,'#763e35',INK,3);}
else if(happy){path(q=>{q.moveTo(-26,49);q.quadraticCurveTo(0,96,28,48);q.closePath();},'#763e35',INK,3);line(-14,55,16,55,PAPER,8);}
- else{path(q=>{q.moveTo(-17,wally?66:52);q.quadraticCurveTo(0,wally?77:66,20,wally?63:49);},null,INK,4);}
- if(!wally)for(const side of [-1,1])for(let j=0;j<3;j++)ellipse(side*(45+j*7),21+(j%2)*7,2,2,'#ae6b53');
- if(wally){group(0,-78+(pose.capLift||0),pose.capTilt||0,()=>{path(q=>{q.moveTo(-83,9);q.bezierCurveTo(-89,-73,68,-97,77,0);q.closePath();},GOLD,INK,6);path(q=>{q.moveTo(-85,1);q.quadraticCurveTo(3,-19,94,-2);q.quadraticCurveTo(124,12,83,24);q.lineTo(-84,20);q.closePath();},'#d5a039',INK,5);line(-51,-32,-12,-46,'#f8d277',7);if(pose.capPaint)splat(44,-21,24,CORAL);});}
+ else{path(q=>{q.moveTo(-17,wallo?66:52);q.quadraticCurveTo(0,wallo?77:66,20,wallo?63:49);},null,INK,4);}
+ if(!wallo)for(const side of [-1,1])for(let j=0;j<3;j++)ellipse(side*(45+j*7),21+(j%2)*7,2,2,'#ae6b53');
+ if(wallo){group(0,-78+(pose.capLift||0),pose.capTilt||0,()=>{path(q=>{q.moveTo(-83,9);q.bezierCurveTo(-89,-73,68,-97,77,0);q.closePath();},GOLD,INK,6);path(q=>{q.moveTo(-85,1);q.quadraticCurveTo(3,-19,94,-2);q.quadraticCurveTo(124,12,83,24);q.lineTo(-84,20);q.closePath();},'#d5a039',INK,5);line(-51,-32,-12,-46,'#f8d277',7);if(pose.capPaint)splat(44,-21,24,CORAL);});}
});
const rh=pose.right||[114+gait*Math.sin(cycle)*43,-257-gait*Math.cos(cycle)*48];
const hand=arm(65,-361,rh[0],rh[1],skin,shirt,-1);
@@ -123,7 +123,7 @@
},scale);
}
function speech(s,x,y,t,at,until,w=330){if(t<at||t>until)return;const a=phase(t,at,at+.22),k=1-Math.pow(1-a,3);group(x,y,0,()=>{rr(-w/2,-41,w,82,24,PAPER,INK,4);path(q=>{q.moveTo(-15,40);q.lineTo(-29,68);q.lineTo(22,40);},PAPER,INK,4);text(s,0,2,30);},k);}
- function punch(t,ep){let p=ease(t,17.3,17.8);if(!p)return;group(540,1763,0,()=>{text(punches[ep],0,0,ep===2?65:72);text('WALLY & PIPPA',0,80,25,INK,'Space Mono');},p);}
+ function punch(t,ep){let p=ease(t,17.3,17.8);if(!p)return;group(540,1763,0,()=>{text(punches[ep],0,0,ep===2?65:72);text('WALLO & PIPPA',0,80,25,INK,'Space Mono');},p);}
function particles(t,start,x,y,dir=1,color=CORAL){let z=t-start;if(z<0||z>1.65)return;for(let i=0;i<32;i++){let vx=dir*(200+rnd(i+1)*370),vy=-410+rnd(i+9)*390;let px=x+vx*z,py=y+vy*z+300*z*z;ellipse(px,py,5+rnd(i+22)*10,7+rnd(i+33)*14,color);}}
function ribbon(t){
const p=ease(t,5,8);c.save();c.globalAlpha=p;
@@ -138,7 +138,7 @@
if(t>=11&&t<15){wx=430;px=674;wp={lean:.10*Math.sin(t*14),right:[132,-467],left:[-111,-431],expr:'shock',headTilt:.13*Math.sin(t*9)};pp={lean:-.10*Math.sin(t*14),right:[124,-461],left:[-131,-472],expr:'shock',headTilt:-.12*Math.sin(t*9)};}
if(t>=15){wx=mix(430,282,ease(t,15,17));px=mix(674,780,ease(t,15,17));wp={left:[-112,-380],right:[110,-478+finish*100],expr:t>17?'laugh':'shock'};pp={left:[-118,-472+finish*100],right:[99,-364],expr:t>17?'laugh':'shock'};}
if(t>5&&t<15)ribbon(t);
- character('wally',wx,1515,t,wp);character('pippa',px,1515,t,pp);
+ character('wallo',wx,1515,t,wp);character('pippa',px,1515,t,pp);
if(t>=3&&t<6){let z=phase(t,3,6);roll(mix(400,784,z),mix(1135,1510,z)-210*Math.sin(z*Math.PI),z*11,.78);}
if(t>=6&&t<11){let z=phase(t,6,11),x=z<.46?mix(784,956,z/.46):mix(956,281,(z-.46)/.54);roll(x,1500-Math.abs(Math.sin(z*Math.PI*3))*85,z*29,.85);}
if(t>=11&&t<15.1){const b=ease(t,11,11.8)*(1-ease(t,14.7,15.1));c.save();c.globalAlpha=b;for(let j=0;j<4;j++){const y=1155+j*81+Math.sin(t*12+j)*7;path(q=>{q.moveTo(326,y);q.bezierCurveTo(425,y+43,697,y-30,783,y+5);},null,INK,58);path(q=>{q.moveTo(326,y);q.bezierCurveTo(425,y+43,697,y-30,783,y+5);},null,'#f4dca0',49);for(let i=0;i<6;i++)leaf(350+i*77,y+10,.3,.3);}c.restore();for(let i=0;i<5;i++)star(490+Math.cos(t*5+i)*149,871+Math.sin(t*5+i)*24,13,GOLD,t);}
@@ -155,7 +155,7 @@
if(t>=10&&t<13){wp={paint:true,expr:'suspicious',headTilt:.13,right:[97,-349],look:1};pp={tool:'roller',right:[113,-253],toolAngle:.35,expr:'suspicious',headTilt:-.25,look:-1};}
if(t>=13&&t<17){wp={paint:true,tool:'roll',right:[114,-467],left:[-94,-354],expr:'smile',lean:.11};pp={right:[104,-349],left:[-133,-443],expr:'laugh',headTilt:.11};}
if(t>=17){wp={paint:true,expr:'laugh',right:[107,-423],headTilt:-.08};pp={expr:'laugh',left:[-116,-420],headTilt:.1};}
- character('wally',287,1515,t,wp);character('pippa',758,1515,t,pp);
+ character('wallo',287,1515,t,wp);character('pippa',758,1515,t,pp);
particles(t,6.9,747,936,-1);speech('JUST A LITTLE FLAIR.',697,697,t,4.2,6.5,430);speech('CALL IT MODERN ART.',579,1100,t,15,17.6,448);punch(t,1);
}
function episodeThree(t){
@@ -169,7 +169,7 @@
if(t>=13&&t<17){wp={tool:'roller',right:[140,-414-Math.sin(t*8)*62],expr:'smile',lean:.14};pp={tool:'roll',right:[-30,-455-Math.sin(t*8)*51],left:[-140,-395],expr:'smile',lean:-.13};}
let high=ease(t,17,17.6),recover=ease(t,18.3,19);let wx=mix(288,347,high),px=mix(766,708,high);
if(t>=17){wp={right:[mix(116,172,high),mix(-352,-450,high)],left:[-112,-344],expr:'laugh',capPaint:t>18.1,headTilt:.07,hop:Math.sin(phase(t,17.2,18.2)*Math.PI)*15};pp={left:[mix(-116,-172,high),mix(-352,-450,high)],right:[110,-342],expr:'laugh',headTilt:-.08,hop:Math.sin(phase(t,17.2,18.2)*Math.PI)*15};if(recover>0){wp.right=[mix(172,115,recover),mix(-450,-382,recover)];pp.left=[mix(-172,-120,recover),mix(-450,-382,recover)];}}
- character('wally',wx,1515,t,wp);character('pippa',px,1515,t,pp);
+ character('wallo',wx,1515,t,wp);character('pippa',px,1515,t,pp);
if(t<3){const n=3-Math.floor(t),p=(t%1);group(538,746,0,()=>{ellipse(0,0,72,72,PAPER,INK,5);text(String(n),0,4,86);},.9+.1*Math.sin(p*Math.PI));}
speech('RACE YOU!',733,702,t,.5,2.5,238);speech('HMM. TEAM UP?',540,714,t,11.3,13.3,333);
if(t>=17.65&&t<18.3){const z=phase(t,17.65,18.3);for(let i=0;i<9;i++){const a=i*Math.PI*2/9;star(526+Math.cos(a)*(25+z*123),1027+Math.sin(a)*(25+z*98),13*(1-z),i%2?GOLD:CORAL,a+z);}}
@@ -177,7 +177,7 @@
}
function draw(t,ep=episode){c.clearRect(0,0,1080,1920);[episodeOne,episodeTwo,episodeThree][ep](clamp(t,0,20));}
window.drawFrame=draw;
- window.exportCharacter=(kind)=>{c.clearRect(0,0,1080,1920);character(kind,540,1410,1,{scale:1.9,tool:kind==='wally'?'roll':'roller',right:[105,-350],expr:'smile'});return canvas.toDataURL('image/png');};
+ window.exportCharacter=(kind)=>{c.clearRect(0,0,1080,1920);character(kind,540,1410,1,{scale:1.9,tool:kind==='wallo'?'roll':'roller',right:[105,-350],expr:'smile'});return canvas.toDataURL('image/png');};
const driver={time:0};
const tl=gsap.timeline({paused:true});
tl.fromTo(driver,{time:0},{time:20,duration:20,ease:'none',onUpdate:()=>draw(driver.time)},0);
diff --git a/assets/wally.png b/assets/wallo.png
similarity index 100%
rename from assets/wally.png
rename to assets/wallo.png
diff --git a/episodes/01-runaway-roll.html b/episodes/01-runaway-roll.html
index 3c5f2b2..9834c02 100644
--- a/episodes/01-runaway-roll.html
+++ b/episodes/01-runaway-roll.html
@@ -1,7 +1,7 @@
<!doctype html>
-<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=1080,height=1920"><title>Wally & Pippa — 01-runaway-roll</title>
+<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=1080,height=1920"><title>Wallo & Pippa — 01-runaway-roll</title>
<style>@font-face{font-family:'Archivo Black';src:url('../assets/archivo.ttf')}@font-face{font-family:'Space Mono';src:url('../assets/space-mono.ttf')}html,body{margin:0;width:1080px;height:1920px;overflow:hidden}#root{position:relative;width:1080px;height:1920px;overflow:hidden}.clip{position:absolute;inset:0;width:1080px;height:1920px}canvas{width:1080px;height:1920px}.font-preload{position:absolute;opacity:0;font-family:'Archivo Black'} .font-preload.mono{font-family:'Space Mono'}</style>
-<script src="../assets/gsap.min.js"></script></head><body data-episode="0"><div id="root" data-composition-id="main" data-start="0" data-width="1080" data-height="1920" data-duration="20" data-fps="30"><section id="cartoon-scene" class="clip" data-start="0" data-duration="20" data-track-index="0"><canvas id="stage" width="1080" height="1920" aria-label="Two animated decorators performing a comedy routine"></canvas><span class="font-preload">Wally</span><span class="font-preload mono">Pippa</span></section><audio id="soundtrack" src="../assets/short-1.wav" data-start="0" data-duration="20" data-track-index="1"></audio></div><script>/* Original Wally & Pippa character rigs. Every pose is a pure function of time. */
+<script src="../assets/gsap.min.js"></script></head><body data-episode="0"><div id="root" data-composition-id="main" data-start="0" data-width="1080" data-height="1920" data-duration="20" data-fps="30"><section id="cartoon-scene" class="clip" data-start="0" data-duration="20" data-track-index="0"><canvas id="stage" width="1080" height="1920" aria-label="Two animated decorators performing a comedy routine"></canvas><span class="font-preload">Wallo</span><span class="font-preload mono">Pippa</span></section><audio id="soundtrack" src="../assets/short-1.wav" data-start="0" data-duration="20" data-track-index="1"></audio></div><script>/* Original Wallo & Pippa character rigs. Every pose is a pure function of time. */
(() => {
'use strict';
const canvas = document.getElementById('stage');
@@ -46,7 +46,7 @@
ellipse(152,1580,90,17,'#b39573');roll(142,1555,-.10,.75);
// Gentle sun shapes, a physical room light rather than a decorative UI effect.
c.save();c.globalAlpha=.18;path(q=>{q.moveTo(76,436);q.lineTo(278,436);q.lineTo(801,1507);q.lineTo(599,1507);q.closePath();},'#fffef0',null);c.restore();
- text('WALLY & PIPPA',65,100,37,TEAL,'Space Mono','left');
+ text('WALLO & PIPPA',65,100,37,TEAL,'Space Mono','left');
text(`SHORT 0${ep+1}`,1014,100,27,INK,'Space Mono','right');
const title=titles[ep];text(title,540,211,ep===1?59:72);
text('TWO DECORATORS. ONE BEAUTIFUL MESS.',540,292,24,INK,'Space Mono');
@@ -65,7 +65,7 @@
return [hx,hy];
}
function character(kind,x,y,t,pose={}){
- const wally=kind==='wally',skin=wally?'#e9ae82':'#f0ba97',shirt=wally?PAPER:CORAL,cloth=wally?TEAL:'#eee7d5';
+ const wallo=kind==='wallo',skin=wallo?'#e9ae82':'#f0ba97',shirt=wallo?PAPER:CORAL,cloth=wallo?TEAL:'#eee7d5';
const gait=pose.run||0,cycle=t*(pose.fast?19:13),kick=pose.kick||0;
const hop=gait*Math.abs(Math.sin(cycle))*19+(pose.hop||0);
const lean=pose.lean||0,scale=pose.scale||1.05,duck=pose.duck||0;
@@ -78,8 +78,8 @@
if(side===-1&&kick){kx-=kick*53;ky-=kick*31;fx-=kick*117;fy-=kick*110;}
path(q=>{q.moveTo(hx,hy);q.lineTo(kx,ky);q.lineTo(fx,fy);},null,INK,54);
path(q=>{q.moveTo(hx,hy);q.lineTo(kx,ky);q.lineTo(fx,fy);},null,cloth,44);
- line(kx+side*10,ky-16,fx+side*10,fy-12,wally?'#419995':'#fff8eb',7);
- group(fx,fy,.06*stride,()=>{rr(-24,-21,72,40,14,wally?'#895b41':'#457889',INK,5);line(-17,11,42,11,INK,7);line(-8,-12,18,-10,wally?'#d4a171':'#91b4be',4);});
+ line(kx+side*10,ky-16,fx+side*10,fy-12,wallo?'#419995':'#fff8eb',7);
+ group(fx,fy,.06*stride,()=>{rr(-24,-21,72,40,14,wallo?'#895b41':'#457889',INK,5);line(-17,11,42,11,INK,7);line(-8,-12,18,-10,wallo?'#d4a171':'#91b4be',4);});
}
const breath=Math.sin(t*3.1)*2.5;
group(0,-duck*0+breath,0,()=>{
@@ -89,33 +89,33 @@
path(q=>{q.moveTo(-58,-390);q.quadraticCurveTo(-91,-375,-82,-319);q.lineTo(-72,-196);q.quadraticCurveTo(0,-166,72,-196);q.lineTo(82,-319);q.quadraticCurveTo(90,-375,57,-390);q.closePath();},shirt,INK,6);
rr(-69,-308,138,139,25,cloth,INK,5);
line(-48,-378,-41,-280,cloth,26);line(48,-378,41,-280,cloth,26);
- for(const s of [-1,1]){ellipse(s*43,-315,7,7,GOLD,INK,3);line(s*42,-369,s*39,-334,wally?'#74b5a8':'#fff9ed',5);}
- rr(-36,-286,72,65,8,wally?'#206b6d':'#dad5c3',INK,4);path(q=>{q.moveTo(-27,-269);q.quadraticCurveTo(0,-239,27,-269);},null,wally?'#71aca0':'#fff8e9',4);
- if(wally){rr(-81,-224,27,60,4,'#b2774d',INK,3);rr(-74,-234,11,41,3,GOLD,INK,2);}else{ellipse(40,-199,10,7,CORAL);ellipse(-26,-234,7,10,TEAL);}
+ for(const s of [-1,1]){ellipse(s*43,-315,7,7,GOLD,INK,3);line(s*42,-369,s*39,-334,wallo?'#74b5a8':'#fff9ed',5);}
+ rr(-36,-286,72,65,8,wallo?'#206b6d':'#dad5c3',INK,4);path(q=>{q.moveTo(-27,-269);q.quadraticCurveTo(0,-239,27,-269);},null,wallo?'#71aca0':'#fff8e9',4);
+ if(wallo){rr(-81,-224,27,60,4,'#b2774d',INK,3);rr(-74,-234,11,41,3,GOLD,INK,2);}else{ellipse(40,-199,10,7,CORAL);ellipse(-26,-234,7,10,TEAL);}
rr(-24,-423,48,55,14,skin,INK,5);
// Hair mass and face with a broad, readable silhouette.
group(pose.headX||0,-500+(pose.headY||0),pose.headTilt||0,()=>{
- if(!wally){ellipse(-2,-34,96,101,'#8b503b',INK,6);ellipse(54,-108,43,43,'#8b503b',INK,5);for(let i=0;i<5;i++)ellipse(36+i*11,-119+(i%2)*13,18,22,i%2?'#a96848':'#8b503b');}
+ if(!wallo){ellipse(-2,-34,96,101,'#8b503b',INK,6);ellipse(54,-108,43,43,'#8b503b',INK,5);for(let i=0;i<5;i++)ellipse(36+i*11,-119+(i%2)*13,18,22,i%2?'#a96848':'#8b503b');}
ellipse(-81,6,18,27,skin,INK,4);ellipse(81,6,18,27,skin,INK,4);
path(q=>{q.moveTo(-74,-44);q.bezierCurveTo(-72,-104,72,-104,75,-41);q.lineTo(74,38);q.bezierCurveTo(69,99,-66,99,-74,37);q.closePath();},skin,INK,6);
ellipse(-58,28,14,8,'#d99074');ellipse(58,28,14,8,'#d99074');
- if(wally){path(q=>{q.moveTo(-78,-37);q.lineTo(-71,-69);q.lineTo(-62,-65);q.lineTo(-62,-31);},'#59483e',null);path(q=>{q.moveTo(62,-68);q.lineTo(78,-46);q.lineTo(74,-24);q.lineTo(62,-31);},'#59483e',null);}
+ if(wallo){path(q=>{q.moveTo(-78,-37);q.lineTo(-71,-69);q.lineTo(-62,-65);q.lineTo(-62,-31);},'#59483e',null);path(q=>{q.moveTo(62,-68);q.lineTo(78,-46);q.lineTo(74,-24);q.lineTo(62,-31);},'#59483e',null);}
else{for(let i=0;i<7;i++)ellipse(-66+i*21,-57-Math.sin(i*.6)*17,21,27,i%2?'#9f6042':'#8b503b',INK,3);}
- const blinking=((t+(wally?0:1.4))%4.1<.13),surprise=pose.expr==='shock',happy=pose.expr==='laugh';
- const look=pose.look??(wally?1:-1);
+ const blinking=((t+(wallo?0:1.4))%4.1<.13),surprise=pose.expr==='shock',happy=pose.expr==='laugh';
+ const look=pose.look??(wallo?1:-1);
for(const s of [-1,1]){
const ex=s*32,ey=-7;
if(blinking||happy){path(q=>{q.moveTo(ex-13,ey+4);q.quadraticCurveTo(ex,ey-10,ex+13,ey+4);},null,INK,5);}
else{ellipse(ex,ey,17,surprise?25:20,'#fffaf1',INK,3);ellipse(ex+look*4,ey+(surprise?2:0),6,10,INK);ellipse(ex+look*4+2,ey-5,2,3,PAPER);}
- const b=surprise?-49:-38;line(ex-12,b+s*(pose.expr==='suspicious'?7:0),ex+12,b+(!wally?3:0),INK,6);
+ const b=surprise?-49:-38;line(ex-12,b+s*(pose.expr==='suspicious'?7:0),ex+12,b+(!wallo?3:0),INK,6);
}
- ellipse(2,17,wally?19:12,wally?18:12,wally?'#de986f':'#eaa887',INK,3);
- if(wally){path(q=>{q.moveTo(0,38);q.bezierCurveTo(-14,25,-26,39,-41,36);q.bezierCurveTo(-33,65,-10,62,0,48);q.bezierCurveTo(13,64,39,57,43,37);q.bezierCurveTo(25,43,16,25,0,38);},pose.paint?CORAL:'#55423a',INK,3);}
- if(surprise){ellipse(0,wally?68:51,11,15,'#763e35',INK,3);}
+ ellipse(2,17,wallo?19:12,wallo?18:12,wallo?'#de986f':'#eaa887',INK,3);
+ if(wallo){path(q=>{q.moveTo(0,38);q.bezierCurveTo(-14,25,-26,39,-41,36);q.bezierCurveTo(-33,65,-10,62,0,48);q.bezierCurveTo(13,64,39,57,43,37);q.bezierCurveTo(25,43,16,25,0,38);},pose.paint?CORAL:'#55423a',INK,3);}
+ if(surprise){ellipse(0,wallo?68:51,11,15,'#763e35',INK,3);}
else if(happy){path(q=>{q.moveTo(-26,49);q.quadraticCurveTo(0,96,28,48);q.closePath();},'#763e35',INK,3);line(-14,55,16,55,PAPER,8);}
- else{path(q=>{q.moveTo(-17,wally?66:52);q.quadraticCurveTo(0,wally?77:66,20,wally?63:49);},null,INK,4);}
- if(!wally)for(const side of [-1,1])for(let j=0;j<3;j++)ellipse(side*(45+j*7),21+(j%2)*7,2,2,'#ae6b53');
- if(wally){group(0,-78+(pose.capLift||0),pose.capTilt||0,()=>{path(q=>{q.moveTo(-83,9);q.bezierCurveTo(-89,-73,68,-97,77,0);q.closePath();},GOLD,INK,6);path(q=>{q.moveTo(-85,1);q.quadraticCurveTo(3,-19,94,-2);q.quadraticCurveTo(124,12,83,24);q.lineTo(-84,20);q.closePath();},'#d5a039',INK,5);line(-51,-32,-12,-46,'#f8d277',7);if(pose.capPaint)splat(44,-21,24,CORAL);});}
+ else{path(q=>{q.moveTo(-17,wallo?66:52);q.quadraticCurveTo(0,wallo?77:66,20,wallo?63:49);},null,INK,4);}
+ if(!wallo)for(const side of [-1,1])for(let j=0;j<3;j++)ellipse(side*(45+j*7),21+(j%2)*7,2,2,'#ae6b53');
+ if(wallo){group(0,-78+(pose.capLift||0),pose.capTilt||0,()=>{path(q=>{q.moveTo(-83,9);q.bezierCurveTo(-89,-73,68,-97,77,0);q.closePath();},GOLD,INK,6);path(q=>{q.moveTo(-85,1);q.quadraticCurveTo(3,-19,94,-2);q.quadraticCurveTo(124,12,83,24);q.lineTo(-84,20);q.closePath();},'#d5a039',INK,5);line(-51,-32,-12,-46,'#f8d277',7);if(pose.capPaint)splat(44,-21,24,CORAL);});}
});
const rh=pose.right||[114+gait*Math.sin(cycle)*43,-257-gait*Math.cos(cycle)*48];
const hand=arm(65,-361,rh[0],rh[1],skin,shirt,-1);
@@ -126,7 +126,7 @@
},scale);
}
function speech(s,x,y,t,at,until,w=330){if(t<at||t>until)return;const a=phase(t,at,at+.22),k=1-Math.pow(1-a,3);group(x,y,0,()=>{rr(-w/2,-41,w,82,24,PAPER,INK,4);path(q=>{q.moveTo(-15,40);q.lineTo(-29,68);q.lineTo(22,40);},PAPER,INK,4);text(s,0,2,30);},k);}
- function punch(t,ep){let p=ease(t,17.3,17.8);if(!p)return;group(540,1763,0,()=>{text(punches[ep],0,0,ep===2?65:72);text('WALLY & PIPPA',0,80,25,INK,'Space Mono');},p);}
+ function punch(t,ep){let p=ease(t,17.3,17.8);if(!p)return;group(540,1763,0,()=>{text(punches[ep],0,0,ep===2?65:72);text('WALLO & PIPPA',0,80,25,INK,'Space Mono');},p);}
function particles(t,start,x,y,dir=1,color=CORAL){let z=t-start;if(z<0||z>1.65)return;for(let i=0;i<32;i++){let vx=dir*(200+rnd(i+1)*370),vy=-410+rnd(i+9)*390;let px=x+vx*z,py=y+vy*z+300*z*z;ellipse(px,py,5+rnd(i+22)*10,7+rnd(i+33)*14,color);}}
function ribbon(t){
const p=ease(t,5,8);c.save();c.globalAlpha=p;
@@ -141,7 +141,7 @@
if(t>=11&&t<15){wx=430;px=674;wp={lean:.10*Math.sin(t*14),right:[132,-467],left:[-111,-431],expr:'shock',headTilt:.13*Math.sin(t*9)};pp={lean:-.10*Math.sin(t*14),right:[124,-461],left:[-131,-472],expr:'shock',headTilt:-.12*Math.sin(t*9)};}
if(t>=15){wx=mix(430,282,ease(t,15,17));px=mix(674,780,ease(t,15,17));wp={left:[-112,-380],right:[110,-478+finish*100],expr:t>17?'laugh':'shock'};pp={left:[-118,-472+finish*100],right:[99,-364],expr:t>17?'laugh':'shock'};}
if(t>5&&t<15)ribbon(t);
- character('wally',wx,1515,t,wp);character('pippa',px,1515,t,pp);
+ character('wallo',wx,1515,t,wp);character('pippa',px,1515,t,pp);
if(t>=3&&t<6){let z=phase(t,3,6);roll(mix(400,784,z),mix(1135,1510,z)-210*Math.sin(z*Math.PI),z*11,.78);}
if(t>=6&&t<11){let z=phase(t,6,11),x=z<.46?mix(784,956,z/.46):mix(956,281,(z-.46)/.54);roll(x,1500-Math.abs(Math.sin(z*Math.PI*3))*85,z*29,.85);}
if(t>=11&&t<15.1){const b=ease(t,11,11.8)*(1-ease(t,14.7,15.1));c.save();c.globalAlpha=b;for(let j=0;j<4;j++){const y=1155+j*81+Math.sin(t*12+j)*7;path(q=>{q.moveTo(326,y);q.bezierCurveTo(425,y+43,697,y-30,783,y+5);},null,INK,58);path(q=>{q.moveTo(326,y);q.bezierCurveTo(425,y+43,697,y-30,783,y+5);},null,'#f4dca0',49);for(let i=0;i<6;i++)leaf(350+i*77,y+10,.3,.3);}c.restore();for(let i=0;i<5;i++)star(490+Math.cos(t*5+i)*149,871+Math.sin(t*5+i)*24,13,GOLD,t);}
@@ -158,7 +158,7 @@
if(t>=10&&t<13){wp={paint:true,expr:'suspicious',headTilt:.13,right:[97,-349],look:1};pp={tool:'roller',right:[113,-253],toolAngle:.35,expr:'suspicious',headTilt:-.25,look:-1};}
if(t>=13&&t<17){wp={paint:true,tool:'roll',right:[114,-467],left:[-94,-354],expr:'smile',lean:.11};pp={right:[104,-349],left:[-133,-443],expr:'laugh',headTilt:.11};}
if(t>=17){wp={paint:true,expr:'laugh',right:[107,-423],headTilt:-.08};pp={expr:'laugh',left:[-116,-420],headTilt:.1};}
- character('wally',287,1515,t,wp);character('pippa',758,1515,t,pp);
+ character('wallo',287,1515,t,wp);character('pippa',758,1515,t,pp);
particles(t,6.9,747,936,-1);speech('JUST A LITTLE FLAIR.',697,697,t,4.2,6.5,430);speech('CALL IT MODERN ART.',579,1100,t,15,17.6,448);punch(t,1);
}
function episodeThree(t){
@@ -172,7 +172,7 @@
if(t>=13&&t<17){wp={tool:'roller',right:[140,-414-Math.sin(t*8)*62],expr:'smile',lean:.14};pp={tool:'roll',right:[-30,-455-Math.sin(t*8)*51],left:[-140,-395],expr:'smile',lean:-.13};}
let high=ease(t,17,17.6),recover=ease(t,18.3,19);let wx=mix(288,347,high),px=mix(766,708,high);
if(t>=17){wp={right:[mix(116,172,high),mix(-352,-450,high)],left:[-112,-344],expr:'laugh',capPaint:t>18.1,headTilt:.07,hop:Math.sin(phase(t,17.2,18.2)*Math.PI)*15};pp={left:[mix(-116,-172,high),mix(-352,-450,high)],right:[110,-342],expr:'laugh',headTilt:-.08,hop:Math.sin(phase(t,17.2,18.2)*Math.PI)*15};if(recover>0){wp.right=[mix(172,115,recover),mix(-450,-382,recover)];pp.left=[mix(-172,-120,recover),mix(-450,-382,recover)];}}
- character('wally',wx,1515,t,wp);character('pippa',px,1515,t,pp);
+ character('wallo',wx,1515,t,wp);character('pippa',px,1515,t,pp);
if(t<3){const n=3-Math.floor(t),p=(t%1);group(538,746,0,()=>{ellipse(0,0,72,72,PAPER,INK,5);text(String(n),0,4,86);},.9+.1*Math.sin(p*Math.PI));}
speech('RACE YOU!',733,702,t,.5,2.5,238);speech('HMM. TEAM UP?',540,714,t,11.3,13.3,333);
if(t>=17.65&&t<18.3){const z=phase(t,17.65,18.3);for(let i=0;i<9;i++){const a=i*Math.PI*2/9;star(526+Math.cos(a)*(25+z*123),1027+Math.sin(a)*(25+z*98),13*(1-z),i%2?GOLD:CORAL,a+z);}}
@@ -180,7 +180,7 @@
}
function draw(t,ep=episode){c.clearRect(0,0,1080,1920);[episodeOne,episodeTwo,episodeThree][ep](clamp(t,0,20));}
window.drawFrame=draw;
- window.exportCharacter=(kind)=>{c.clearRect(0,0,1080,1920);character(kind,540,1410,1,{scale:1.9,tool:kind==='wally'?'roll':'roller',right:[105,-350],expr:'smile'});return canvas.toDataURL('image/png');};
+ window.exportCharacter=(kind)=>{c.clearRect(0,0,1080,1920);character(kind,540,1410,1,{scale:1.9,tool:kind==='wallo'?'roll':'roller',right:[105,-350],expr:'smile'});return canvas.toDataURL('image/png');};
const driver={time:0};
const tl=gsap.timeline({paused:true});
tl.fromTo(driver,{time:0},{time:20,duration:20,ease:'none',onUpdate:()=>draw(driver.time)},0);
diff --git a/episodes/02-splash-of-personality.html b/episodes/02-splash-of-personality.html
index 9d827f5..e42a8b0 100644
--- a/episodes/02-splash-of-personality.html
+++ b/episodes/02-splash-of-personality.html
@@ -1,7 +1,7 @@
<!doctype html>
-<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=1080,height=1920"><title>Wally & Pippa — 02-splash-of-personality</title>
+<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=1080,height=1920"><title>Wallo & Pippa — 02-splash-of-personality</title>
<style>@font-face{font-family:'Archivo Black';src:url('../assets/archivo.ttf')}@font-face{font-family:'Space Mono';src:url('../assets/space-mono.ttf')}html,body{margin:0;width:1080px;height:1920px;overflow:hidden}#root{position:relative;width:1080px;height:1920px;overflow:hidden}.clip{position:absolute;inset:0;width:1080px;height:1920px}canvas{width:1080px;height:1920px}.font-preload{position:absolute;opacity:0;font-family:'Archivo Black'} .font-preload.mono{font-family:'Space Mono'}</style>
-<script src="../assets/gsap.min.js"></script></head><body data-episode="1"><div id="root" data-composition-id="main" data-start="0" data-width="1080" data-height="1920" data-duration="20" data-fps="30"><section id="cartoon-scene" class="clip" data-start="0" data-duration="20" data-track-index="0"><canvas id="stage" width="1080" height="1920" aria-label="Two animated decorators performing a comedy routine"></canvas><span class="font-preload">Wally</span><span class="font-preload mono">Pippa</span></section><audio id="soundtrack" src="../assets/short-2.wav" data-start="0" data-duration="20" data-track-index="1"></audio></div><script>/* Original Wally & Pippa character rigs. Every pose is a pure function of time. */
+<script src="../assets/gsap.min.js"></script></head><body data-episode="1"><div id="root" data-composition-id="main" data-start="0" data-width="1080" data-height="1920" data-duration="20" data-fps="30"><section id="cartoon-scene" class="clip" data-start="0" data-duration="20" data-track-index="0"><canvas id="stage" width="1080" height="1920" aria-label="Two animated decorators performing a comedy routine"></canvas><span class="font-preload">Wallo</span><span class="font-preload mono">Pippa</span></section><audio id="soundtrack" src="../assets/short-2.wav" data-start="0" data-duration="20" data-track-index="1"></audio></div><script>/* Original Wallo & Pippa character rigs. Every pose is a pure function of time. */
(() => {
'use strict';
const canvas = document.getElementById('stage');
@@ -46,7 +46,7 @@
ellipse(152,1580,90,17,'#b39573');roll(142,1555,-.10,.75);
// Gentle sun shapes, a physical room light rather than a decorative UI effect.
c.save();c.globalAlpha=.18;path(q=>{q.moveTo(76,436);q.lineTo(278,436);q.lineTo(801,1507);q.lineTo(599,1507);q.closePath();},'#fffef0',null);c.restore();
- text('WALLY & PIPPA',65,100,37,TEAL,'Space Mono','left');
+ text('WALLO & PIPPA',65,100,37,TEAL,'Space Mono','left');
text(`SHORT 0${ep+1}`,1014,100,27,INK,'Space Mono','right');
const title=titles[ep];text(title,540,211,ep===1?59:72);
text('TWO DECORATORS. ONE BEAUTIFUL MESS.',540,292,24,INK,'Space Mono');
@@ -65,7 +65,7 @@
return [hx,hy];
}
function character(kind,x,y,t,pose={}){
- const wally=kind==='wally',skin=wally?'#e9ae82':'#f0ba97',shirt=wally?PAPER:CORAL,cloth=wally?TEAL:'#eee7d5';
+ const wallo=kind==='wallo',skin=wallo?'#e9ae82':'#f0ba97',shirt=wallo?PAPER:CORAL,cloth=wallo?TEAL:'#eee7d5';
const gait=pose.run||0,cycle=t*(pose.fast?19:13),kick=pose.kick||0;
const hop=gait*Math.abs(Math.sin(cycle))*19+(pose.hop||0);
const lean=pose.lean||0,scale=pose.scale||1.05,duck=pose.duck||0;
@@ -78,8 +78,8 @@
if(side===-1&&kick){kx-=kick*53;ky-=kick*31;fx-=kick*117;fy-=kick*110;}
path(q=>{q.moveTo(hx,hy);q.lineTo(kx,ky);q.lineTo(fx,fy);},null,INK,54);
path(q=>{q.moveTo(hx,hy);q.lineTo(kx,ky);q.lineTo(fx,fy);},null,cloth,44);
- line(kx+side*10,ky-16,fx+side*10,fy-12,wally?'#419995':'#fff8eb',7);
- group(fx,fy,.06*stride,()=>{rr(-24,-21,72,40,14,wally?'#895b41':'#457889',INK,5);line(-17,11,42,11,INK,7);line(-8,-12,18,-10,wally?'#d4a171':'#91b4be',4);});
+ line(kx+side*10,ky-16,fx+side*10,fy-12,wallo?'#419995':'#fff8eb',7);
+ group(fx,fy,.06*stride,()=>{rr(-24,-21,72,40,14,wallo?'#895b41':'#457889',INK,5);line(-17,11,42,11,INK,7);line(-8,-12,18,-10,wallo?'#d4a171':'#91b4be',4);});
}
const breath=Math.sin(t*3.1)*2.5;
group(0,-duck*0+breath,0,()=>{
@@ -89,33 +89,33 @@
path(q=>{q.moveTo(-58,-390);q.quadraticCurveTo(-91,-375,-82,-319);q.lineTo(-72,-196);q.quadraticCurveTo(0,-166,72,-196);q.lineTo(82,-319);q.quadraticCurveTo(90,-375,57,-390);q.closePath();},shirt,INK,6);
rr(-69,-308,138,139,25,cloth,INK,5);
line(-48,-378,-41,-280,cloth,26);line(48,-378,41,-280,cloth,26);
- for(const s of [-1,1]){ellipse(s*43,-315,7,7,GOLD,INK,3);line(s*42,-369,s*39,-334,wally?'#74b5a8':'#fff9ed',5);}
- rr(-36,-286,72,65,8,wally?'#206b6d':'#dad5c3',INK,4);path(q=>{q.moveTo(-27,-269);q.quadraticCurveTo(0,-239,27,-269);},null,wally?'#71aca0':'#fff8e9',4);
- if(wally){rr(-81,-224,27,60,4,'#b2774d',INK,3);rr(-74,-234,11,41,3,GOLD,INK,2);}else{ellipse(40,-199,10,7,CORAL);ellipse(-26,-234,7,10,TEAL);}
+ for(const s of [-1,1]){ellipse(s*43,-315,7,7,GOLD,INK,3);line(s*42,-369,s*39,-334,wallo?'#74b5a8':'#fff9ed',5);}
+ rr(-36,-286,72,65,8,wallo?'#206b6d':'#dad5c3',INK,4);path(q=>{q.moveTo(-27,-269);q.quadraticCurveTo(0,-239,27,-269);},null,wallo?'#71aca0':'#fff8e9',4);
+ if(wallo){rr(-81,-224,27,60,4,'#b2774d',INK,3);rr(-74,-234,11,41,3,GOLD,INK,2);}else{ellipse(40,-199,10,7,CORAL);ellipse(-26,-234,7,10,TEAL);}
rr(-24,-423,48,55,14,skin,INK,5);
// Hair mass and face with a broad, readable silhouette.
group(pose.headX||0,-500+(pose.headY||0),pose.headTilt||0,()=>{
- if(!wally){ellipse(-2,-34,96,101,'#8b503b',INK,6);ellipse(54,-108,43,43,'#8b503b',INK,5);for(let i=0;i<5;i++)ellipse(36+i*11,-119+(i%2)*13,18,22,i%2?'#a96848':'#8b503b');}
+ if(!wallo){ellipse(-2,-34,96,101,'#8b503b',INK,6);ellipse(54,-108,43,43,'#8b503b',INK,5);for(let i=0;i<5;i++)ellipse(36+i*11,-119+(i%2)*13,18,22,i%2?'#a96848':'#8b503b');}
ellipse(-81,6,18,27,skin,INK,4);ellipse(81,6,18,27,skin,INK,4);
path(q=>{q.moveTo(-74,-44);q.bezierCurveTo(-72,-104,72,-104,75,-41);q.lineTo(74,38);q.bezierCurveTo(69,99,-66,99,-74,37);q.closePath();},skin,INK,6);
ellipse(-58,28,14,8,'#d99074');ellipse(58,28,14,8,'#d99074');
- if(wally){path(q=>{q.moveTo(-78,-37);q.lineTo(-71,-69);q.lineTo(-62,-65);q.lineTo(-62,-31);},'#59483e',null);path(q=>{q.moveTo(62,-68);q.lineTo(78,-46);q.lineTo(74,-24);q.lineTo(62,-31);},'#59483e',null);}
+ if(wallo){path(q=>{q.moveTo(-78,-37);q.lineTo(-71,-69);q.lineTo(-62,-65);q.lineTo(-62,-31);},'#59483e',null);path(q=>{q.moveTo(62,-68);q.lineTo(78,-46);q.lineTo(74,-24);q.lineTo(62,-31);},'#59483e',null);}
else{for(let i=0;i<7;i++)ellipse(-66+i*21,-57-Math.sin(i*.6)*17,21,27,i%2?'#9f6042':'#8b503b',INK,3);}
- const blinking=((t+(wally?0:1.4))%4.1<.13),surprise=pose.expr==='shock',happy=pose.expr==='laugh';
- const look=pose.look??(wally?1:-1);
+ const blinking=((t+(wallo?0:1.4))%4.1<.13),surprise=pose.expr==='shock',happy=pose.expr==='laugh';
+ const look=pose.look??(wallo?1:-1);
for(const s of [-1,1]){
const ex=s*32,ey=-7;
if(blinking||happy){path(q=>{q.moveTo(ex-13,ey+4);q.quadraticCurveTo(ex,ey-10,ex+13,ey+4);},null,INK,5);}
else{ellipse(ex,ey,17,surprise?25:20,'#fffaf1',INK,3);ellipse(ex+look*4,ey+(surprise?2:0),6,10,INK);ellipse(ex+look*4+2,ey-5,2,3,PAPER);}
- const b=surprise?-49:-38;line(ex-12,b+s*(pose.expr==='suspicious'?7:0),ex+12,b+(!wally?3:0),INK,6);
+ const b=surprise?-49:-38;line(ex-12,b+s*(pose.expr==='suspicious'?7:0),ex+12,b+(!wallo?3:0),INK,6);
}
- ellipse(2,17,wally?19:12,wally?18:12,wally?'#de986f':'#eaa887',INK,3);
- if(wally){path(q=>{q.moveTo(0,38);q.bezierCurveTo(-14,25,-26,39,-41,36);q.bezierCurveTo(-33,65,-10,62,0,48);q.bezierCurveTo(13,64,39,57,43,37);q.bezierCurveTo(25,43,16,25,0,38);},pose.paint?CORAL:'#55423a',INK,3);}
- if(surprise){ellipse(0,wally?68:51,11,15,'#763e35',INK,3);}
+ ellipse(2,17,wallo?19:12,wallo?18:12,wallo?'#de986f':'#eaa887',INK,3);
+ if(wallo){path(q=>{q.moveTo(0,38);q.bezierCurveTo(-14,25,-26,39,-41,36);q.bezierCurveTo(-33,65,-10,62,0,48);q.bezierCurveTo(13,64,39,57,43,37);q.bezierCurveTo(25,43,16,25,0,38);},pose.paint?CORAL:'#55423a',INK,3);}
+ if(surprise){ellipse(0,wallo?68:51,11,15,'#763e35',INK,3);}
else if(happy){path(q=>{q.moveTo(-26,49);q.quadraticCurveTo(0,96,28,48);q.closePath();},'#763e35',INK,3);line(-14,55,16,55,PAPER,8);}
- else{path(q=>{q.moveTo(-17,wally?66:52);q.quadraticCurveTo(0,wally?77:66,20,wally?63:49);},null,INK,4);}
- if(!wally)for(const side of [-1,1])for(let j=0;j<3;j++)ellipse(side*(45+j*7),21+(j%2)*7,2,2,'#ae6b53');
- if(wally){group(0,-78+(pose.capLift||0),pose.capTilt||0,()=>{path(q=>{q.moveTo(-83,9);q.bezierCurveTo(-89,-73,68,-97,77,0);q.closePath();},GOLD,INK,6);path(q=>{q.moveTo(-85,1);q.quadraticCurveTo(3,-19,94,-2);q.quadraticCurveTo(124,12,83,24);q.lineTo(-84,20);q.closePath();},'#d5a039',INK,5);line(-51,-32,-12,-46,'#f8d277',7);if(pose.capPaint)splat(44,-21,24,CORAL);});}
+ else{path(q=>{q.moveTo(-17,wallo?66:52);q.quadraticCurveTo(0,wallo?77:66,20,wallo?63:49);},null,INK,4);}
+ if(!wallo)for(const side of [-1,1])for(let j=0;j<3;j++)ellipse(side*(45+j*7),21+(j%2)*7,2,2,'#ae6b53');
+ if(wallo){group(0,-78+(pose.capLift||0),pose.capTilt||0,()=>{path(q=>{q.moveTo(-83,9);q.bezierCurveTo(-89,-73,68,-97,77,0);q.closePath();},GOLD,INK,6);path(q=>{q.moveTo(-85,1);q.quadraticCurveTo(3,-19,94,-2);q.quadraticCurveTo(124,12,83,24);q.lineTo(-84,20);q.closePath();},'#d5a039',INK,5);line(-51,-32,-12,-46,'#f8d277',7);if(pose.capPaint)splat(44,-21,24,CORAL);});}
});
const rh=pose.right||[114+gait*Math.sin(cycle)*43,-257-gait*Math.cos(cycle)*48];
const hand=arm(65,-361,rh[0],rh[1],skin,shirt,-1);
@@ -126,7 +126,7 @@
},scale);
}
function speech(s,x,y,t,at,until,w=330){if(t<at||t>until)return;const a=phase(t,at,at+.22),k=1-Math.pow(1-a,3);group(x,y,0,()=>{rr(-w/2,-41,w,82,24,PAPER,INK,4);path(q=>{q.moveTo(-15,40);q.lineTo(-29,68);q.lineTo(22,40);},PAPER,INK,4);text(s,0,2,30);},k);}
- function punch(t,ep){let p=ease(t,17.3,17.8);if(!p)return;group(540,1763,0,()=>{text(punches[ep],0,0,ep===2?65:72);text('WALLY & PIPPA',0,80,25,INK,'Space Mono');},p);}
+ function punch(t,ep){let p=ease(t,17.3,17.8);if(!p)return;group(540,1763,0,()=>{text(punches[ep],0,0,ep===2?65:72);text('WALLO & PIPPA',0,80,25,INK,'Space Mono');},p);}
function particles(t,start,x,y,dir=1,color=CORAL){let z=t-start;if(z<0||z>1.65)return;for(let i=0;i<32;i++){let vx=dir*(200+rnd(i+1)*370),vy=-410+rnd(i+9)*390;let px=x+vx*z,py=y+vy*z+300*z*z;ellipse(px,py,5+rnd(i+22)*10,7+rnd(i+33)*14,color);}}
function ribbon(t){
const p=ease(t,5,8);c.save();c.globalAlpha=p;
@@ -141,7 +141,7 @@
if(t>=11&&t<15){wx=430;px=674;wp={lean:.10*Math.sin(t*14),right:[132,-467],left:[-111,-431],expr:'shock',headTilt:.13*Math.sin(t*9)};pp={lean:-.10*Math.sin(t*14),right:[124,-461],left:[-131,-472],expr:'shock',headTilt:-.12*Math.sin(t*9)};}
if(t>=15){wx=mix(430,282,ease(t,15,17));px=mix(674,780,ease(t,15,17));wp={left:[-112,-380],right:[110,-478+finish*100],expr:t>17?'laugh':'shock'};pp={left:[-118,-472+finish*100],right:[99,-364],expr:t>17?'laugh':'shock'};}
if(t>5&&t<15)ribbon(t);
- character('wally',wx,1515,t,wp);character('pippa',px,1515,t,pp);
+ character('wallo',wx,1515,t,wp);character('pippa',px,1515,t,pp);
if(t>=3&&t<6){let z=phase(t,3,6);roll(mix(400,784,z),mix(1135,1510,z)-210*Math.sin(z*Math.PI),z*11,.78);}
if(t>=6&&t<11){let z=phase(t,6,11),x=z<.46?mix(784,956,z/.46):mix(956,281,(z-.46)/.54);roll(x,1500-Math.abs(Math.sin(z*Math.PI*3))*85,z*29,.85);}
if(t>=11&&t<15.1){const b=ease(t,11,11.8)*(1-ease(t,14.7,15.1));c.save();c.globalAlpha=b;for(let j=0;j<4;j++){const y=1155+j*81+Math.sin(t*12+j)*7;path(q=>{q.moveTo(326,y);q.bezierCurveTo(425,y+43,697,y-30,783,y+5);},null,INK,58);path(q=>{q.moveTo(326,y);q.bezierCurveTo(425,y+43,697,y-30,783,y+5);},null,'#f4dca0',49);for(let i=0;i<6;i++)leaf(350+i*77,y+10,.3,.3);}c.restore();for(let i=0;i<5;i++)star(490+Math.cos(t*5+i)*149,871+Math.sin(t*5+i)*24,13,GOLD,t);}
@@ -158,7 +158,7 @@
if(t>=10&&t<13){wp={paint:true,expr:'suspicious',headTilt:.13,right:[97,-349],look:1};pp={tool:'roller',right:[113,-253],toolAngle:.35,expr:'suspicious',headTilt:-.25,look:-1};}
if(t>=13&&t<17){wp={paint:true,tool:'roll',right:[114,-467],left:[-94,-354],expr:'smile',lean:.11};pp={right:[104,-349],left:[-133,-443],expr:'laugh',headTilt:.11};}
if(t>=17){wp={paint:true,expr:'laugh',right:[107,-423],headTilt:-.08};pp={expr:'laugh',left:[-116,-420],headTilt:.1};}
- character('wally',287,1515,t,wp);character('pippa',758,1515,t,pp);
+ character('wallo',287,1515,t,wp);character('pippa',758,1515,t,pp);
particles(t,6.9,747,936,-1);speech('JUST A LITTLE FLAIR.',697,697,t,4.2,6.5,430);speech('CALL IT MODERN ART.',579,1100,t,15,17.6,448);punch(t,1);
}
function episodeThree(t){
@@ -172,7 +172,7 @@
if(t>=13&&t<17){wp={tool:'roller',right:[140,-414-Math.sin(t*8)*62],expr:'smile',lean:.14};pp={tool:'roll',right:[-30,-455-Math.sin(t*8)*51],left:[-140,-395],expr:'smile',lean:-.13};}
let high=ease(t,17,17.6),recover=ease(t,18.3,19);let wx=mix(288,347,high),px=mix(766,708,high);
if(t>=17){wp={right:[mix(116,172,high),mix(-352,-450,high)],left:[-112,-344],expr:'laugh',capPaint:t>18.1,headTilt:.07,hop:Math.sin(phase(t,17.2,18.2)*Math.PI)*15};pp={left:[mix(-116,-172,high),mix(-352,-450,high)],right:[110,-342],expr:'laugh',headTilt:-.08,hop:Math.sin(phase(t,17.2,18.2)*Math.PI)*15};if(recover>0){wp.right=[mix(172,115,recover),mix(-450,-382,recover)];pp.left=[mix(-172,-120,recover),mix(-450,-382,recover)];}}
- character('wally',wx,1515,t,wp);character('pippa',px,1515,t,pp);
+ character('wallo',wx,1515,t,wp);character('pippa',px,1515,t,pp);
if(t<3){const n=3-Math.floor(t),p=(t%1);group(538,746,0,()=>{ellipse(0,0,72,72,PAPER,INK,5);text(String(n),0,4,86);},.9+.1*Math.sin(p*Math.PI));}
speech('RACE YOU!',733,702,t,.5,2.5,238);speech('HMM. TEAM UP?',540,714,t,11.3,13.3,333);
if(t>=17.65&&t<18.3){const z=phase(t,17.65,18.3);for(let i=0;i<9;i++){const a=i*Math.PI*2/9;star(526+Math.cos(a)*(25+z*123),1027+Math.sin(a)*(25+z*98),13*(1-z),i%2?GOLD:CORAL,a+z);}}
@@ -180,7 +180,7 @@
}
function draw(t,ep=episode){c.clearRect(0,0,1080,1920);[episodeOne,episodeTwo,episodeThree][ep](clamp(t,0,20));}
window.drawFrame=draw;
- window.exportCharacter=(kind)=>{c.clearRect(0,0,1080,1920);character(kind,540,1410,1,{scale:1.9,tool:kind==='wally'?'roll':'roller',right:[105,-350],expr:'smile'});return canvas.toDataURL('image/png');};
+ window.exportCharacter=(kind)=>{c.clearRect(0,0,1080,1920);character(kind,540,1410,1,{scale:1.9,tool:kind==='wallo'?'roll':'roller',right:[105,-350],expr:'smile'});return canvas.toDataURL('image/png');};
const driver={time:0};
const tl=gsap.timeline({paused:true});
tl.fromTo(driver,{time:0},{time:20,duration:20,ease:'none',onUpdate:()=>draw(driver.time)},0);
diff --git a/episodes/03-great-wall-off.html b/episodes/03-great-wall-off.html
index 2338fdf..5f6f4d5 100644
--- a/episodes/03-great-wall-off.html
+++ b/episodes/03-great-wall-off.html
@@ -1,7 +1,7 @@
<!doctype html>
-<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=1080,height=1920"><title>Wally & Pippa — 03-great-wall-off</title>
+<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=1080,height=1920"><title>Wallo & Pippa — 03-great-wall-off</title>
<style>@font-face{font-family:'Archivo Black';src:url('../assets/archivo.ttf')}@font-face{font-family:'Space Mono';src:url('../assets/space-mono.ttf')}html,body{margin:0;width:1080px;height:1920px;overflow:hidden}#root{position:relative;width:1080px;height:1920px;overflow:hidden}.clip{position:absolute;inset:0;width:1080px;height:1920px}canvas{width:1080px;height:1920px}.font-preload{position:absolute;opacity:0;font-family:'Archivo Black'} .font-preload.mono{font-family:'Space Mono'}</style>
-<script src="../assets/gsap.min.js"></script></head><body data-episode="2"><div id="root" data-composition-id="main" data-start="0" data-width="1080" data-height="1920" data-duration="20" data-fps="30"><section id="cartoon-scene" class="clip" data-start="0" data-duration="20" data-track-index="0"><canvas id="stage" width="1080" height="1920" aria-label="Two animated decorators performing a comedy routine"></canvas><span class="font-preload">Wally</span><span class="font-preload mono">Pippa</span></section><audio id="soundtrack" src="../assets/short-3.wav" data-start="0" data-duration="20" data-track-index="1"></audio></div><script>/* Original Wally & Pippa character rigs. Every pose is a pure function of time. */
+<script src="../assets/gsap.min.js"></script></head><body data-episode="2"><div id="root" data-composition-id="main" data-start="0" data-width="1080" data-height="1920" data-duration="20" data-fps="30"><section id="cartoon-scene" class="clip" data-start="0" data-duration="20" data-track-index="0"><canvas id="stage" width="1080" height="1920" aria-label="Two animated decorators performing a comedy routine"></canvas><span class="font-preload">Wallo</span><span class="font-preload mono">Pippa</span></section><audio id="soundtrack" src="../assets/short-3.wav" data-start="0" data-duration="20" data-track-index="1"></audio></div><script>/* Original Wallo & Pippa character rigs. Every pose is a pure function of time. */
(() => {
'use strict';
const canvas = document.getElementById('stage');
@@ -46,7 +46,7 @@
ellipse(152,1580,90,17,'#b39573');roll(142,1555,-.10,.75);
// Gentle sun shapes, a physical room light rather than a decorative UI effect.
c.save();c.globalAlpha=.18;path(q=>{q.moveTo(76,436);q.lineTo(278,436);q.lineTo(801,1507);q.lineTo(599,1507);q.closePath();},'#fffef0',null);c.restore();
- text('WALLY & PIPPA',65,100,37,TEAL,'Space Mono','left');
+ text('WALLO & PIPPA',65,100,37,TEAL,'Space Mono','left');
text(`SHORT 0${ep+1}`,1014,100,27,INK,'Space Mono','right');
const title=titles[ep];text(title,540,211,ep===1?59:72);
text('TWO DECORATORS. ONE BEAUTIFUL MESS.',540,292,24,INK,'Space Mono');
@@ -65,7 +65,7 @@
return [hx,hy];
}
function character(kind,x,y,t,pose={}){
- const wally=kind==='wally',skin=wally?'#e9ae82':'#f0ba97',shirt=wally?PAPER:CORAL,cloth=wally?TEAL:'#eee7d5';
+ const wallo=kind==='wallo',skin=wallo?'#e9ae82':'#f0ba97',shirt=wallo?PAPER:CORAL,cloth=wallo?TEAL:'#eee7d5';
const gait=pose.run||0,cycle=t*(pose.fast?19:13),kick=pose.kick||0;
const hop=gait*Math.abs(Math.sin(cycle))*19+(pose.hop||0);
const lean=pose.lean||0,scale=pose.scale||1.05,duck=pose.duck||0;
@@ -78,8 +78,8 @@
if(side===-1&&kick){kx-=kick*53;ky-=kick*31;fx-=kick*117;fy-=kick*110;}
path(q=>{q.moveTo(hx,hy);q.lineTo(kx,ky);q.lineTo(fx,fy);},null,INK,54);
path(q=>{q.moveTo(hx,hy);q.lineTo(kx,ky);q.lineTo(fx,fy);},null,cloth,44);
- line(kx+side*10,ky-16,fx+side*10,fy-12,wally?'#419995':'#fff8eb',7);
- group(fx,fy,.06*stride,()=>{rr(-24,-21,72,40,14,wally?'#895b41':'#457889',INK,5);line(-17,11,42,11,INK,7);line(-8,-12,18,-10,wally?'#d4a171':'#91b4be',4);});
+ line(kx+side*10,ky-16,fx+side*10,fy-12,wallo?'#419995':'#fff8eb',7);
+ group(fx,fy,.06*stride,()=>{rr(-24,-21,72,40,14,wallo?'#895b41':'#457889',INK,5);line(-17,11,42,11,INK,7);line(-8,-12,18,-10,wallo?'#d4a171':'#91b4be',4);});
}
const breath=Math.sin(t*3.1)*2.5;
group(0,-duck*0+breath,0,()=>{
@@ -89,33 +89,33 @@
path(q=>{q.moveTo(-58,-390);q.quadraticCurveTo(-91,-375,-82,-319);q.lineTo(-72,-196);q.quadraticCurveTo(0,-166,72,-196);q.lineTo(82,-319);q.quadraticCurveTo(90,-375,57,-390);q.closePath();},shirt,INK,6);
rr(-69,-308,138,139,25,cloth,INK,5);
line(-48,-378,-41,-280,cloth,26);line(48,-378,41,-280,cloth,26);
- for(const s of [-1,1]){ellipse(s*43,-315,7,7,GOLD,INK,3);line(s*42,-369,s*39,-334,wally?'#74b5a8':'#fff9ed',5);}
- rr(-36,-286,72,65,8,wally?'#206b6d':'#dad5c3',INK,4);path(q=>{q.moveTo(-27,-269);q.quadraticCurveTo(0,-239,27,-269);},null,wally?'#71aca0':'#fff8e9',4);
- if(wally){rr(-81,-224,27,60,4,'#b2774d',INK,3);rr(-74,-234,11,41,3,GOLD,INK,2);}else{ellipse(40,-199,10,7,CORAL);ellipse(-26,-234,7,10,TEAL);}
+ for(const s of [-1,1]){ellipse(s*43,-315,7,7,GOLD,INK,3);line(s*42,-369,s*39,-334,wallo?'#74b5a8':'#fff9ed',5);}
+ rr(-36,-286,72,65,8,wallo?'#206b6d':'#dad5c3',INK,4);path(q=>{q.moveTo(-27,-269);q.quadraticCurveTo(0,-239,27,-269);},null,wallo?'#71aca0':'#fff8e9',4);
+ if(wallo){rr(-81,-224,27,60,4,'#b2774d',INK,3);rr(-74,-234,11,41,3,GOLD,INK,2);}else{ellipse(40,-199,10,7,CORAL);ellipse(-26,-234,7,10,TEAL);}
rr(-24,-423,48,55,14,skin,INK,5);
// Hair mass and face with a broad, readable silhouette.
group(pose.headX||0,-500+(pose.headY||0),pose.headTilt||0,()=>{
- if(!wally){ellipse(-2,-34,96,101,'#8b503b',INK,6);ellipse(54,-108,43,43,'#8b503b',INK,5);for(let i=0;i<5;i++)ellipse(36+i*11,-119+(i%2)*13,18,22,i%2?'#a96848':'#8b503b');}
+ if(!wallo){ellipse(-2,-34,96,101,'#8b503b',INK,6);ellipse(54,-108,43,43,'#8b503b',INK,5);for(let i=0;i<5;i++)ellipse(36+i*11,-119+(i%2)*13,18,22,i%2?'#a96848':'#8b503b');}
ellipse(-81,6,18,27,skin,INK,4);ellipse(81,6,18,27,skin,INK,4);
path(q=>{q.moveTo(-74,-44);q.bezierCurveTo(-72,-104,72,-104,75,-41);q.lineTo(74,38);q.bezierCurveTo(69,99,-66,99,-74,37);q.closePath();},skin,INK,6);
ellipse(-58,28,14,8,'#d99074');ellipse(58,28,14,8,'#d99074');
- if(wally){path(q=>{q.moveTo(-78,-37);q.lineTo(-71,-69);q.lineTo(-62,-65);q.lineTo(-62,-31);},'#59483e',null);path(q=>{q.moveTo(62,-68);q.lineTo(78,-46);q.lineTo(74,-24);q.lineTo(62,-31);},'#59483e',null);}
+ if(wallo){path(q=>{q.moveTo(-78,-37);q.lineTo(-71,-69);q.lineTo(-62,-65);q.lineTo(-62,-31);},'#59483e',null);path(q=>{q.moveTo(62,-68);q.lineTo(78,-46);q.lineTo(74,-24);q.lineTo(62,-31);},'#59483e',null);}
else{for(let i=0;i<7;i++)ellipse(-66+i*21,-57-Math.sin(i*.6)*17,21,27,i%2?'#9f6042':'#8b503b',INK,3);}
- const blinking=((t+(wally?0:1.4))%4.1<.13),surprise=pose.expr==='shock',happy=pose.expr==='laugh';
- const look=pose.look??(wally?1:-1);
+ const blinking=((t+(wallo?0:1.4))%4.1<.13),surprise=pose.expr==='shock',happy=pose.expr==='laugh';
+ const look=pose.look??(wallo?1:-1);
for(const s of [-1,1]){
const ex=s*32,ey=-7;
if(blinking||happy){path(q=>{q.moveTo(ex-13,ey+4);q.quadraticCurveTo(ex,ey-10,ex+13,ey+4);},null,INK,5);}
else{ellipse(ex,ey,17,surprise?25:20,'#fffaf1',INK,3);ellipse(ex+look*4,ey+(surprise?2:0),6,10,INK);ellipse(ex+look*4+2,ey-5,2,3,PAPER);}
- const b=surprise?-49:-38;line(ex-12,b+s*(pose.expr==='suspicious'?7:0),ex+12,b+(!wally?3:0),INK,6);
+ const b=surprise?-49:-38;line(ex-12,b+s*(pose.expr==='suspicious'?7:0),ex+12,b+(!wallo?3:0),INK,6);
}
- ellipse(2,17,wally?19:12,wally?18:12,wally?'#de986f':'#eaa887',INK,3);
- if(wally){path(q=>{q.moveTo(0,38);q.bezierCurveTo(-14,25,-26,39,-41,36);q.bezierCurveTo(-33,65,-10,62,0,48);q.bezierCurveTo(13,64,39,57,43,37);q.bezierCurveTo(25,43,16,25,0,38);},pose.paint?CORAL:'#55423a',INK,3);}
- if(surprise){ellipse(0,wally?68:51,11,15,'#763e35',INK,3);}
+ ellipse(2,17,wallo?19:12,wallo?18:12,wallo?'#de986f':'#eaa887',INK,3);
+ if(wallo){path(q=>{q.moveTo(0,38);q.bezierCurveTo(-14,25,-26,39,-41,36);q.bezierCurveTo(-33,65,-10,62,0,48);q.bezierCurveTo(13,64,39,57,43,37);q.bezierCurveTo(25,43,16,25,0,38);},pose.paint?CORAL:'#55423a',INK,3);}
+ if(surprise){ellipse(0,wallo?68:51,11,15,'#763e35',INK,3);}
else if(happy){path(q=>{q.moveTo(-26,49);q.quadraticCurveTo(0,96,28,48);q.closePath();},'#763e35',INK,3);line(-14,55,16,55,PAPER,8);}
- else{path(q=>{q.moveTo(-17,wally?66:52);q.quadraticCurveTo(0,wally?77:66,20,wally?63:49);},null,INK,4);}
- if(!wally)for(const side of [-1,1])for(let j=0;j<3;j++)ellipse(side*(45+j*7),21+(j%2)*7,2,2,'#ae6b53');
- if(wally){group(0,-78+(pose.capLift||0),pose.capTilt||0,()=>{path(q=>{q.moveTo(-83,9);q.bezierCurveTo(-89,-73,68,-97,77,0);q.closePath();},GOLD,INK,6);path(q=>{q.moveTo(-85,1);q.quadraticCurveTo(3,-19,94,-2);q.quadraticCurveTo(124,12,83,24);q.lineTo(-84,20);q.closePath();},'#d5a039',INK,5);line(-51,-32,-12,-46,'#f8d277',7);if(pose.capPaint)splat(44,-21,24,CORAL);});}
+ else{path(q=>{q.moveTo(-17,wallo?66:52);q.quadraticCurveTo(0,wallo?77:66,20,wallo?63:49);},null,INK,4);}
+ if(!wallo)for(const side of [-1,1])for(let j=0;j<3;j++)ellipse(side*(45+j*7),21+(j%2)*7,2,2,'#ae6b53');
+ if(wallo){group(0,-78+(pose.capLift||0),pose.capTilt||0,()=>{path(q=>{q.moveTo(-83,9);q.bezierCurveTo(-89,-73,68,-97,77,0);q.closePath();},GOLD,INK,6);path(q=>{q.moveTo(-85,1);q.quadraticCurveTo(3,-19,94,-2);q.quadraticCurveTo(124,12,83,24);q.lineTo(-84,20);q.closePath();},'#d5a039',INK,5);line(-51,-32,-12,-46,'#f8d277',7);if(pose.capPaint)splat(44,-21,24,CORAL);});}
});
const rh=pose.right||[114+gait*Math.sin(cycle)*43,-257-gait*Math.cos(cycle)*48];
const hand=arm(65,-361,rh[0],rh[1],skin,shirt,-1);
@@ -126,7 +126,7 @@
},scale);
}
function speech(s,x,y,t,at,until,w=330){if(t<at||t>until)return;const a=phase(t,at,at+.22),k=1-Math.pow(1-a,3);group(x,y,0,()=>{rr(-w/2,-41,w,82,24,PAPER,INK,4);path(q=>{q.moveTo(-15,40);q.lineTo(-29,68);q.lineTo(22,40);},PAPER,INK,4);text(s,0,2,30);},k);}
- function punch(t,ep){let p=ease(t,17.3,17.8);if(!p)return;group(540,1763,0,()=>{text(punches[ep],0,0,ep===2?65:72);text('WALLY & PIPPA',0,80,25,INK,'Space Mono');},p);}
+ function punch(t,ep){let p=ease(t,17.3,17.8);if(!p)return;group(540,1763,0,()=>{text(punches[ep],0,0,ep===2?65:72);text('WALLO & PIPPA',0,80,25,INK,'Space Mono');},p);}
function particles(t,start,x,y,dir=1,color=CORAL){let z=t-start;if(z<0||z>1.65)return;for(let i=0;i<32;i++){let vx=dir*(200+rnd(i+1)*370),vy=-410+rnd(i+9)*390;let px=x+vx*z,py=y+vy*z+300*z*z;ellipse(px,py,5+rnd(i+22)*10,7+rnd(i+33)*14,color);}}
function ribbon(t){
const p=ease(t,5,8);c.save();c.globalAlpha=p;
@@ -141,7 +141,7 @@
if(t>=11&&t<15){wx=430;px=674;wp={lean:.10*Math.sin(t*14),right:[132,-467],left:[-111,-431],expr:'shock',headTilt:.13*Math.sin(t*9)};pp={lean:-.10*Math.sin(t*14),right:[124,-461],left:[-131,-472],expr:'shock',headTilt:-.12*Math.sin(t*9)};}
if(t>=15){wx=mix(430,282,ease(t,15,17));px=mix(674,780,ease(t,15,17));wp={left:[-112,-380],right:[110,-478+finish*100],expr:t>17?'laugh':'shock'};pp={left:[-118,-472+finish*100],right:[99,-364],expr:t>17?'laugh':'shock'};}
if(t>5&&t<15)ribbon(t);
- character('wally',wx,1515,t,wp);character('pippa',px,1515,t,pp);
+ character('wallo',wx,1515,t,wp);character('pippa',px,1515,t,pp);
if(t>=3&&t<6){let z=phase(t,3,6);roll(mix(400,784,z),mix(1135,1510,z)-210*Math.sin(z*Math.PI),z*11,.78);}
if(t>=6&&t<11){let z=phase(t,6,11),x=z<.46?mix(784,956,z/.46):mix(956,281,(z-.46)/.54);roll(x,1500-Math.abs(Math.sin(z*Math.PI*3))*85,z*29,.85);}
if(t>=11&&t<15.1){const b=ease(t,11,11.8)*(1-ease(t,14.7,15.1));c.save();c.globalAlpha=b;for(let j=0;j<4;j++){const y=1155+j*81+Math.sin(t*12+j)*7;path(q=>{q.moveTo(326,y);q.bezierCurveTo(425,y+43,697,y-30,783,y+5);},null,INK,58);path(q=>{q.moveTo(326,y);q.bezierCurveTo(425,y+43,697,y-30,783,y+5);},null,'#f4dca0',49);for(let i=0;i<6;i++)leaf(350+i*77,y+10,.3,.3);}c.restore();for(let i=0;i<5;i++)star(490+Math.cos(t*5+i)*149,871+Math.sin(t*5+i)*24,13,GOLD,t);}
@@ -158,7 +158,7 @@
if(t>=10&&t<13){wp={paint:true,expr:'suspicious',headTilt:.13,right:[97,-349],look:1};pp={tool:'roller',right:[113,-253],toolAngle:.35,expr:'suspicious',headTilt:-.25,look:-1};}
if(t>=13&&t<17){wp={paint:true,tool:'roll',right:[114,-467],left:[-94,-354],expr:'smile',lean:.11};pp={right:[104,-349],left:[-133,-443],expr:'laugh',headTilt:.11};}
if(t>=17){wp={paint:true,expr:'laugh',right:[107,-423],headTilt:-.08};pp={expr:'laugh',left:[-116,-420],headTilt:.1};}
- character('wally',287,1515,t,wp);character('pippa',758,1515,t,pp);
+ character('wallo',287,1515,t,wp);character('pippa',758,1515,t,pp);
particles(t,6.9,747,936,-1);speech('JUST A LITTLE FLAIR.',697,697,t,4.2,6.5,430);speech('CALL IT MODERN ART.',579,1100,t,15,17.6,448);punch(t,1);
}
function episodeThree(t){
@@ -172,7 +172,7 @@
if(t>=13&&t<17){wp={tool:'roller',right:[140,-414-Math.sin(t*8)*62],expr:'smile',lean:.14};pp={tool:'roll',right:[-30,-455-Math.sin(t*8)*51],left:[-140,-395],expr:'smile',lean:-.13};}
let high=ease(t,17,17.6),recover=ease(t,18.3,19);let wx=mix(288,347,high),px=mix(766,708,high);
if(t>=17){wp={right:[mix(116,172,high),mix(-352,-450,high)],left:[-112,-344],expr:'laugh',capPaint:t>18.1,headTilt:.07,hop:Math.sin(phase(t,17.2,18.2)*Math.PI)*15};pp={left:[mix(-116,-172,high),mix(-352,-450,high)],right:[110,-342],expr:'laugh',headTilt:-.08,hop:Math.sin(phase(t,17.2,18.2)*Math.PI)*15};if(recover>0){wp.right=[mix(172,115,recover),mix(-450,-382,recover)];pp.left=[mix(-172,-120,recover),mix(-450,-382,recover)];}}
- character('wally',wx,1515,t,wp);character('pippa',px,1515,t,pp);
+ character('wallo',wx,1515,t,wp);character('pippa',px,1515,t,pp);
if(t<3){const n=3-Math.floor(t),p=(t%1);group(538,746,0,()=>{ellipse(0,0,72,72,PAPER,INK,5);text(String(n),0,4,86);},.9+.1*Math.sin(p*Math.PI));}
speech('RACE YOU!',733,702,t,.5,2.5,238);speech('HMM. TEAM UP?',540,714,t,11.3,13.3,333);
if(t>=17.65&&t<18.3){const z=phase(t,17.65,18.3);for(let i=0;i<9;i++){const a=i*Math.PI*2/9;star(526+Math.cos(a)*(25+z*123),1027+Math.sin(a)*(25+z*98),13*(1-z),i%2?GOLD:CORAL,a+z);}}
@@ -180,7 +180,7 @@
}
function draw(t,ep=episode){c.clearRect(0,0,1080,1920);[episodeOne,episodeTwo,episodeThree][ep](clamp(t,0,20));}
window.drawFrame=draw;
- window.exportCharacter=(kind)=>{c.clearRect(0,0,1080,1920);character(kind,540,1410,1,{scale:1.9,tool:kind==='wally'?'roll':'roller',right:[105,-350],expr:'smile'});return canvas.toDataURL('image/png');};
+ window.exportCharacter=(kind)=>{c.clearRect(0,0,1080,1920);character(kind,540,1410,1,{scale:1.9,tool:kind==='wallo'?'roll':'roller',right:[105,-350],expr:'smile'});return canvas.toDataURL('image/png');};
const driver={time:0};
const tl=gsap.timeline({paused:true});
tl.fromTo(driver,{time:0},{time:20,duration:20,ease:'none',onUpdate:()=>draw(driver.time)},0);
diff --git a/index.html b/index.html
index 49c499f..780ba9a 100644
--- a/index.html
+++ b/index.html
@@ -1,7 +1,7 @@
<!doctype html>
-<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=1080,height=1920"><title>Wally & Pippa — 01-runaway-roll</title>
+<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=1080,height=1920"><title>Wallo & Pippa — 01-runaway-roll</title>
<style>@font-face{font-family:'Archivo Black';src:url('assets/archivo.ttf')}@font-face{font-family:'Space Mono';src:url('assets/space-mono.ttf')}html,body{margin:0;width:1080px;height:1920px;overflow:hidden}#root{position:relative;width:1080px;height:1920px;overflow:hidden}.clip{position:absolute;inset:0;width:1080px;height:1920px}canvas{width:1080px;height:1920px}.font-preload{position:absolute;opacity:0;font-family:'Archivo Black'} .font-preload.mono{font-family:'Space Mono'}</style>
-<script src="assets/gsap.min.js"></script></head><body data-episode="0"><div id="root" data-composition-id="main" data-start="0" data-width="1080" data-height="1920" data-duration="20" data-fps="30"><section id="cartoon-scene" class="clip" data-start="0" data-duration="20" data-track-index="0"><canvas id="stage" width="1080" height="1920" aria-label="Two animated decorators performing a comedy routine"></canvas><span class="font-preload">Wally</span><span class="font-preload mono">Pippa</span></section><audio id="soundtrack" src="assets/short-1.wav" data-start="0" data-duration="20" data-track-index="1"></audio></div><script>/* Original Wally & Pippa character rigs. Every pose is a pure function of time. */
+<script src="assets/gsap.min.js"></script></head><body data-episode="0"><div id="root" data-composition-id="main" data-start="0" data-width="1080" data-height="1920" data-duration="20" data-fps="30"><section id="cartoon-scene" class="clip" data-start="0" data-duration="20" data-track-index="0"><canvas id="stage" width="1080" height="1920" aria-label="Two animated decorators performing a comedy routine"></canvas><span class="font-preload">Wallo</span><span class="font-preload mono">Pippa</span></section><audio id="soundtrack" src="assets/short-1.wav" data-start="0" data-duration="20" data-track-index="1"></audio></div><script>/* Original Wallo & Pippa character rigs. Every pose is a pure function of time. */
(() => {
'use strict';
const canvas = document.getElementById('stage');
@@ -46,7 +46,7 @@
ellipse(152,1580,90,17,'#b39573');roll(142,1555,-.10,.75);
// Gentle sun shapes, a physical room light rather than a decorative UI effect.
c.save();c.globalAlpha=.18;path(q=>{q.moveTo(76,436);q.lineTo(278,436);q.lineTo(801,1507);q.lineTo(599,1507);q.closePath();},'#fffef0',null);c.restore();
- text('WALLY & PIPPA',65,100,37,TEAL,'Space Mono','left');
+ text('WALLO & PIPPA',65,100,37,TEAL,'Space Mono','left');
text(`SHORT 0${ep+1}`,1014,100,27,INK,'Space Mono','right');
const title=titles[ep];text(title,540,211,ep===1?59:72);
text('TWO DECORATORS. ONE BEAUTIFUL MESS.',540,292,24,INK,'Space Mono');
@@ -65,7 +65,7 @@
return [hx,hy];
}
function character(kind,x,y,t,pose={}){
- const wally=kind==='wally',skin=wally?'#e9ae82':'#f0ba97',shirt=wally?PAPER:CORAL,cloth=wally?TEAL:'#eee7d5';
+ const wallo=kind==='wallo',skin=wallo?'#e9ae82':'#f0ba97',shirt=wallo?PAPER:CORAL,cloth=wallo?TEAL:'#eee7d5';
const gait=pose.run||0,cycle=t*(pose.fast?19:13),kick=pose.kick||0;
const hop=gait*Math.abs(Math.sin(cycle))*19+(pose.hop||0);
const lean=pose.lean||0,scale=pose.scale||1.05,duck=pose.duck||0;
@@ -78,8 +78,8 @@
if(side===-1&&kick){kx-=kick*53;ky-=kick*31;fx-=kick*117;fy-=kick*110;}
path(q=>{q.moveTo(hx,hy);q.lineTo(kx,ky);q.lineTo(fx,fy);},null,INK,54);
path(q=>{q.moveTo(hx,hy);q.lineTo(kx,ky);q.lineTo(fx,fy);},null,cloth,44);
- line(kx+side*10,ky-16,fx+side*10,fy-12,wally?'#419995':'#fff8eb',7);
- group(fx,fy,.06*stride,()=>{rr(-24,-21,72,40,14,wally?'#895b41':'#457889',INK,5);line(-17,11,42,11,INK,7);line(-8,-12,18,-10,wally?'#d4a171':'#91b4be',4);});
+ line(kx+side*10,ky-16,fx+side*10,fy-12,wallo?'#419995':'#fff8eb',7);
+ group(fx,fy,.06*stride,()=>{rr(-24,-21,72,40,14,wallo?'#895b41':'#457889',INK,5);line(-17,11,42,11,INK,7);line(-8,-12,18,-10,wallo?'#d4a171':'#91b4be',4);});
}
const breath=Math.sin(t*3.1)*2.5;
group(0,-duck*0+breath,0,()=>{
@@ -89,33 +89,33 @@
path(q=>{q.moveTo(-58,-390);q.quadraticCurveTo(-91,-375,-82,-319);q.lineTo(-72,-196);q.quadraticCurveTo(0,-166,72,-196);q.lineTo(82,-319);q.quadraticCurveTo(90,-375,57,-390);q.closePath();},shirt,INK,6);
rr(-69,-308,138,139,25,cloth,INK,5);
line(-48,-378,-41,-280,cloth,26);line(48,-378,41,-280,cloth,26);
- for(const s of [-1,1]){ellipse(s*43,-315,7,7,GOLD,INK,3);line(s*42,-369,s*39,-334,wally?'#74b5a8':'#fff9ed',5);}
- rr(-36,-286,72,65,8,wally?'#206b6d':'#dad5c3',INK,4);path(q=>{q.moveTo(-27,-269);q.quadraticCurveTo(0,-239,27,-269);},null,wally?'#71aca0':'#fff8e9',4);
- if(wally){rr(-81,-224,27,60,4,'#b2774d',INK,3);rr(-74,-234,11,41,3,GOLD,INK,2);}else{ellipse(40,-199,10,7,CORAL);ellipse(-26,-234,7,10,TEAL);}
+ for(const s of [-1,1]){ellipse(s*43,-315,7,7,GOLD,INK,3);line(s*42,-369,s*39,-334,wallo?'#74b5a8':'#fff9ed',5);}
+ rr(-36,-286,72,65,8,wallo?'#206b6d':'#dad5c3',INK,4);path(q=>{q.moveTo(-27,-269);q.quadraticCurveTo(0,-239,27,-269);},null,wallo?'#71aca0':'#fff8e9',4);
+ if(wallo){rr(-81,-224,27,60,4,'#b2774d',INK,3);rr(-74,-234,11,41,3,GOLD,INK,2);}else{ellipse(40,-199,10,7,CORAL);ellipse(-26,-234,7,10,TEAL);}
rr(-24,-423,48,55,14,skin,INK,5);
// Hair mass and face with a broad, readable silhouette.
group(pose.headX||0,-500+(pose.headY||0),pose.headTilt||0,()=>{
- if(!wally){ellipse(-2,-34,96,101,'#8b503b',INK,6);ellipse(54,-108,43,43,'#8b503b',INK,5);for(let i=0;i<5;i++)ellipse(36+i*11,-119+(i%2)*13,18,22,i%2?'#a96848':'#8b503b');}
+ if(!wallo){ellipse(-2,-34,96,101,'#8b503b',INK,6);ellipse(54,-108,43,43,'#8b503b',INK,5);for(let i=0;i<5;i++)ellipse(36+i*11,-119+(i%2)*13,18,22,i%2?'#a96848':'#8b503b');}
ellipse(-81,6,18,27,skin,INK,4);ellipse(81,6,18,27,skin,INK,4);
path(q=>{q.moveTo(-74,-44);q.bezierCurveTo(-72,-104,72,-104,75,-41);q.lineTo(74,38);q.bezierCurveTo(69,99,-66,99,-74,37);q.closePath();},skin,INK,6);
ellipse(-58,28,14,8,'#d99074');ellipse(58,28,14,8,'#d99074');
- if(wally){path(q=>{q.moveTo(-78,-37);q.lineTo(-71,-69);q.lineTo(-62,-65);q.lineTo(-62,-31);},'#59483e',null);path(q=>{q.moveTo(62,-68);q.lineTo(78,-46);q.lineTo(74,-24);q.lineTo(62,-31);},'#59483e',null);}
+ if(wallo){path(q=>{q.moveTo(-78,-37);q.lineTo(-71,-69);q.lineTo(-62,-65);q.lineTo(-62,-31);},'#59483e',null);path(q=>{q.moveTo(62,-68);q.lineTo(78,-46);q.lineTo(74,-24);q.lineTo(62,-31);},'#59483e',null);}
else{for(let i=0;i<7;i++)ellipse(-66+i*21,-57-Math.sin(i*.6)*17,21,27,i%2?'#9f6042':'#8b503b',INK,3);}
- const blinking=((t+(wally?0:1.4))%4.1<.13),surprise=pose.expr==='shock',happy=pose.expr==='laugh';
- const look=pose.look??(wally?1:-1);
+ const blinking=((t+(wallo?0:1.4))%4.1<.13),surprise=pose.expr==='shock',happy=pose.expr==='laugh';
+ const look=pose.look??(wallo?1:-1);
for(const s of [-1,1]){
const ex=s*32,ey=-7;
if(blinking||happy){path(q=>{q.moveTo(ex-13,ey+4);q.quadraticCurveTo(ex,ey-10,ex+13,ey+4);},null,INK,5);}
else{ellipse(ex,ey,17,surprise?25:20,'#fffaf1',INK,3);ellipse(ex+look*4,ey+(surprise?2:0),6,10,INK);ellipse(ex+look*4+2,ey-5,2,3,PAPER);}
- const b=surprise?-49:-38;line(ex-12,b+s*(pose.expr==='suspicious'?7:0),ex+12,b+(!wally?3:0),INK,6);
+ const b=surprise?-49:-38;line(ex-12,b+s*(pose.expr==='suspicious'?7:0),ex+12,b+(!wallo?3:0),INK,6);
}
- ellipse(2,17,wally?19:12,wally?18:12,wally?'#de986f':'#eaa887',INK,3);
- if(wally){path(q=>{q.moveTo(0,38);q.bezierCurveTo(-14,25,-26,39,-41,36);q.bezierCurveTo(-33,65,-10,62,0,48);q.bezierCurveTo(13,64,39,57,43,37);q.bezierCurveTo(25,43,16,25,0,38);},pose.paint?CORAL:'#55423a',INK,3);}
- if(surprise){ellipse(0,wally?68:51,11,15,'#763e35',INK,3);}
+ ellipse(2,17,wallo?19:12,wallo?18:12,wallo?'#de986f':'#eaa887',INK,3);
+ if(wallo){path(q=>{q.moveTo(0,38);q.bezierCurveTo(-14,25,-26,39,-41,36);q.bezierCurveTo(-33,65,-10,62,0,48);q.bezierCurveTo(13,64,39,57,43,37);q.bezierCurveTo(25,43,16,25,0,38);},pose.paint?CORAL:'#55423a',INK,3);}
+ if(surprise){ellipse(0,wallo?68:51,11,15,'#763e35',INK,3);}
else if(happy){path(q=>{q.moveTo(-26,49);q.quadraticCurveTo(0,96,28,48);q.closePath();},'#763e35',INK,3);line(-14,55,16,55,PAPER,8);}
- else{path(q=>{q.moveTo(-17,wally?66:52);q.quadraticCurveTo(0,wally?77:66,20,wally?63:49);},null,INK,4);}
- if(!wally)for(const side of [-1,1])for(let j=0;j<3;j++)ellipse(side*(45+j*7),21+(j%2)*7,2,2,'#ae6b53');
- if(wally){group(0,-78+(pose.capLift||0),pose.capTilt||0,()=>{path(q=>{q.moveTo(-83,9);q.bezierCurveTo(-89,-73,68,-97,77,0);q.closePath();},GOLD,INK,6);path(q=>{q.moveTo(-85,1);q.quadraticCurveTo(3,-19,94,-2);q.quadraticCurveTo(124,12,83,24);q.lineTo(-84,20);q.closePath();},'#d5a039',INK,5);line(-51,-32,-12,-46,'#f8d277',7);if(pose.capPaint)splat(44,-21,24,CORAL);});}
+ else{path(q=>{q.moveTo(-17,wallo?66:52);q.quadraticCurveTo(0,wallo?77:66,20,wallo?63:49);},null,INK,4);}
+ if(!wallo)for(const side of [-1,1])for(let j=0;j<3;j++)ellipse(side*(45+j*7),21+(j%2)*7,2,2,'#ae6b53');
+ if(wallo){group(0,-78+(pose.capLift||0),pose.capTilt||0,()=>{path(q=>{q.moveTo(-83,9);q.bezierCurveTo(-89,-73,68,-97,77,0);q.closePath();},GOLD,INK,6);path(q=>{q.moveTo(-85,1);q.quadraticCurveTo(3,-19,94,-2);q.quadraticCurveTo(124,12,83,24);q.lineTo(-84,20);q.closePath();},'#d5a039',INK,5);line(-51,-32,-12,-46,'#f8d277',7);if(pose.capPaint)splat(44,-21,24,CORAL);});}
});
const rh=pose.right||[114+gait*Math.sin(cycle)*43,-257-gait*Math.cos(cycle)*48];
const hand=arm(65,-361,rh[0],rh[1],skin,shirt,-1);
@@ -126,7 +126,7 @@
},scale);
}
function speech(s,x,y,t,at,until,w=330){if(t<at||t>until)return;const a=phase(t,at,at+.22),k=1-Math.pow(1-a,3);group(x,y,0,()=>{rr(-w/2,-41,w,82,24,PAPER,INK,4);path(q=>{q.moveTo(-15,40);q.lineTo(-29,68);q.lineTo(22,40);},PAPER,INK,4);text(s,0,2,30);},k);}
- function punch(t,ep){let p=ease(t,17.3,17.8);if(!p)return;group(540,1763,0,()=>{text(punches[ep],0,0,ep===2?65:72);text('WALLY & PIPPA',0,80,25,INK,'Space Mono');},p);}
+ function punch(t,ep){let p=ease(t,17.3,17.8);if(!p)return;group(540,1763,0,()=>{text(punches[ep],0,0,ep===2?65:72);text('WALLO & PIPPA',0,80,25,INK,'Space Mono');},p);}
function particles(t,start,x,y,dir=1,color=CORAL){let z=t-start;if(z<0||z>1.65)return;for(let i=0;i<32;i++){let vx=dir*(200+rnd(i+1)*370),vy=-410+rnd(i+9)*390;let px=x+vx*z,py=y+vy*z+300*z*z;ellipse(px,py,5+rnd(i+22)*10,7+rnd(i+33)*14,color);}}
function ribbon(t){
const p=ease(t,5,8);c.save();c.globalAlpha=p;
@@ -141,7 +141,7 @@
if(t>=11&&t<15){wx=430;px=674;wp={lean:.10*Math.sin(t*14),right:[132,-467],left:[-111,-431],expr:'shock',headTilt:.13*Math.sin(t*9)};pp={lean:-.10*Math.sin(t*14),right:[124,-461],left:[-131,-472],expr:'shock',headTilt:-.12*Math.sin(t*9)};}
if(t>=15){wx=mix(430,282,ease(t,15,17));px=mix(674,780,ease(t,15,17));wp={left:[-112,-380],right:[110,-478+finish*100],expr:t>17?'laugh':'shock'};pp={left:[-118,-472+finish*100],right:[99,-364],expr:t>17?'laugh':'shock'};}
if(t>5&&t<15)ribbon(t);
- character('wally',wx,1515,t,wp);character('pippa',px,1515,t,pp);
+ character('wallo',wx,1515,t,wp);character('pippa',px,1515,t,pp);
if(t>=3&&t<6){let z=phase(t,3,6);roll(mix(400,784,z),mix(1135,1510,z)-210*Math.sin(z*Math.PI),z*11,.78);}
if(t>=6&&t<11){let z=phase(t,6,11),x=z<.46?mix(784,956,z/.46):mix(956,281,(z-.46)/.54);roll(x,1500-Math.abs(Math.sin(z*Math.PI*3))*85,z*29,.85);}
if(t>=11&&t<15.1){const b=ease(t,11,11.8)*(1-ease(t,14.7,15.1));c.save();c.globalAlpha=b;for(let j=0;j<4;j++){const y=1155+j*81+Math.sin(t*12+j)*7;path(q=>{q.moveTo(326,y);q.bezierCurveTo(425,y+43,697,y-30,783,y+5);},null,INK,58);path(q=>{q.moveTo(326,y);q.bezierCurveTo(425,y+43,697,y-30,783,y+5);},null,'#f4dca0',49);for(let i=0;i<6;i++)leaf(350+i*77,y+10,.3,.3);}c.restore();for(let i=0;i<5;i++)star(490+Math.cos(t*5+i)*149,871+Math.sin(t*5+i)*24,13,GOLD,t);}
@@ -158,7 +158,7 @@
if(t>=10&&t<13){wp={paint:true,expr:'suspicious',headTilt:.13,right:[97,-349],look:1};pp={tool:'roller',right:[113,-253],toolAngle:.35,expr:'suspicious',headTilt:-.25,look:-1};}
if(t>=13&&t<17){wp={paint:true,tool:'roll',right:[114,-467],left:[-94,-354],expr:'smile',lean:.11};pp={right:[104,-349],left:[-133,-443],expr:'laugh',headTilt:.11};}
if(t>=17){wp={paint:true,expr:'laugh',right:[107,-423],headTilt:-.08};pp={expr:'laugh',left:[-116,-420],headTilt:.1};}
- character('wally',287,1515,t,wp);character('pippa',758,1515,t,pp);
+ character('wallo',287,1515,t,wp);character('pippa',758,1515,t,pp);
particles(t,6.9,747,936,-1);speech('JUST A LITTLE FLAIR.',697,697,t,4.2,6.5,430);speech('CALL IT MODERN ART.',579,1100,t,15,17.6,448);punch(t,1);
}
function episodeThree(t){
@@ -172,7 +172,7 @@
if(t>=13&&t<17){wp={tool:'roller',right:[140,-414-Math.sin(t*8)*62],expr:'smile',lean:.14};pp={tool:'roll',right:[-30,-455-Math.sin(t*8)*51],left:[-140,-395],expr:'smile',lean:-.13};}
let high=ease(t,17,17.6),recover=ease(t,18.3,19);let wx=mix(288,347,high),px=mix(766,708,high);
if(t>=17){wp={right:[mix(116,172,high),mix(-352,-450,high)],left:[-112,-344],expr:'laugh',capPaint:t>18.1,headTilt:.07,hop:Math.sin(phase(t,17.2,18.2)*Math.PI)*15};pp={left:[mix(-116,-172,high),mix(-352,-450,high)],right:[110,-342],expr:'laugh',headTilt:-.08,hop:Math.sin(phase(t,17.2,18.2)*Math.PI)*15};if(recover>0){wp.right=[mix(172,115,recover),mix(-450,-382,recover)];pp.left=[mix(-172,-120,recover),mix(-450,-382,recover)];}}
- character('wally',wx,1515,t,wp);character('pippa',px,1515,t,pp);
+ character('wallo',wx,1515,t,wp);character('pippa',px,1515,t,pp);
if(t<3){const n=3-Math.floor(t),p=(t%1);group(538,746,0,()=>{ellipse(0,0,72,72,PAPER,INK,5);text(String(n),0,4,86);},.9+.1*Math.sin(p*Math.PI));}
speech('RACE YOU!',733,702,t,.5,2.5,238);speech('HMM. TEAM UP?',540,714,t,11.3,13.3,333);
if(t>=17.65&&t<18.3){const z=phase(t,17.65,18.3);for(let i=0;i<9;i++){const a=i*Math.PI*2/9;star(526+Math.cos(a)*(25+z*123),1027+Math.sin(a)*(25+z*98),13*(1-z),i%2?GOLD:CORAL,a+z);}}
@@ -180,7 +180,7 @@
}
function draw(t,ep=episode){c.clearRect(0,0,1080,1920);[episodeOne,episodeTwo,episodeThree][ep](clamp(t,0,20));}
window.drawFrame=draw;
- window.exportCharacter=(kind)=>{c.clearRect(0,0,1080,1920);character(kind,540,1410,1,{scale:1.9,tool:kind==='wally'?'roll':'roller',right:[105,-350],expr:'smile'});return canvas.toDataURL('image/png');};
+ window.exportCharacter=(kind)=>{c.clearRect(0,0,1080,1920);character(kind,540,1410,1,{scale:1.9,tool:kind==='wallo'?'roll':'roller',right:[105,-350],expr:'smile'});return canvas.toDataURL('image/png');};
const driver={time:0};
const tl=gsap.timeline({paused:true});
tl.fromTo(driver,{time:0},{time:20,duration:20,ease:'none',onUpdate:()=>draw(driver.time)},0);
diff --git a/scripts/build.mjs b/scripts/build.mjs
index 6032df1..ed89ec0 100644
--- a/scripts/build.mjs
+++ b/scripts/build.mjs
@@ -5,9 +5,9 @@ const slugs=['01-runaway-roll','02-splash-of-personality','03-great-wall-off'];
fs.mkdirSync(path.join(root,'episodes'),{recursive:true});
for(let i=0;i<3;i++){
const html=`<!doctype html>
-<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=1080,height=1920"><title>Wally & Pippa — ${slugs[i]}</title>
+<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=1080,height=1920"><title>Wallo & Pippa — ${slugs[i]}</title>
<style>@font-face{font-family:'Archivo Black';src:url('assets/archivo.ttf')}@font-face{font-family:'Space Mono';src:url('assets/space-mono.ttf')}html,body{margin:0;width:1080px;height:1920px;overflow:hidden}#root{position:relative;width:1080px;height:1920px;overflow:hidden}.clip{position:absolute;inset:0;width:1080px;height:1920px}canvas{width:1080px;height:1920px}.font-preload{position:absolute;opacity:0;font-family:'Archivo Black'} .font-preload.mono{font-family:'Space Mono'}</style>
-<script src="assets/gsap.min.js"></script></head><body data-episode="${i}"><div id="root" data-composition-id="main" data-start="0" data-width="1080" data-height="1920" data-duration="20" data-fps="30"><section class="clip" data-start="0" data-duration="20" data-track-index="0"><canvas id="stage" width="1080" height="1920" aria-label="Two animated decorators performing a comedy routine"></canvas><span class="font-preload">Wally</span><span class="font-preload mono">Pippa</span></section><audio id="soundtrack" src="assets/short-${i+1}.wav" data-start="0" data-duration="20" data-track-index="1"></audio></div><script src="animation.js"></script></body></html>`;
+<script src="assets/gsap.min.js"></script></head><body data-episode="${i}"><div id="root" data-composition-id="main" data-start="0" data-width="1080" data-height="1920" data-duration="20" data-fps="30"><section class="clip" data-start="0" data-duration="20" data-track-index="0"><canvas id="stage" width="1080" height="1920" aria-label="Two animated decorators performing a comedy routine"></canvas><span class="font-preload">Wallo</span><span class="font-preload mono">Pippa</span></section><audio id="soundtrack" src="assets/short-${i+1}.wav" data-start="0" data-duration="20" data-track-index="1"></audio></div><script src="animation.js"></script></body></html>`;
const bundled=html.replace('<section class="clip"','<section id="cartoon-scene" class="clip"').replace('<script src="animation.js"></script>','<script>'+fs.readFileSync(path.join(root,'animation.js'),'utf8')+'</script>');
fs.writeFileSync(path.join(root,'episodes',slugs[i]+'.html'),bundled.replaceAll('assets/','../assets/'));
if(i===0)fs.writeFileSync(path.join(root,'index.html'),bundled);
diff --git a/scripts/mcp-proof.mjs b/scripts/mcp-proof.mjs
index 4968df0..2528cee 100644
--- a/scripts/mcp-proof.mjs
+++ b/scripts/mcp-proof.mjs
@@ -8,8 +8,8 @@ import path from 'node:path';
import assert from 'node:assert/strict';
const root=path.resolve(import.meta.dirname,'..');
const evidence={tool:'chrome-devtools-mcp',version:'1.8.0',mode:'isolated headless',ticket:'TK-11286',at:new Date().toISOString(),calls:[]};
-const client=new Client({name:'wally-pippa-proof',version:'1.0.0'},{capabilities:{roots:{listChanged:false}}});
-client.setRequestHandler(ListRootsRequestSchema,()=>({roots:[{uri:'file://'+root,name:'Wally and Pippa video project'}]}));
+const client=new Client({name:'wallo-pippa-proof',version:'1.0.0'},{capabilities:{roots:{listChanged:false}}});
+client.setRequestHandler(ListRootsRequestSchema,()=>({roots:[{uri:'file://'+root,name:'Wallo and Pippa video project'}]}));
const transport=new StdioClientTransport({command:process.execPath,args:['/Users/macstudio3/.npm/_npx/15c61037b1978c83/node_modules/chrome-devtools-mcp/build/src/bin/chrome-devtools-mcp.js','--isolated','--headless','--no-usage-statistics','--no-performance-crux','--viewport=1440x1400'],stderr:'pipe'});
let stderr='';
async function call(name,args){let result=await client.callTool({name,arguments:args},undefined,{timeout:30000});evidence.calls.push({name,args,result});if(result.isError)throw new Error(JSON.stringify(result));return result;}
@@ -26,7 +26,7 @@ try{
await call('take_screenshot',{pageId,filePath:path.join(root,'verification','mcp-gallery.png'),fullPage:true});
// Export the reusable character PNGs through MCP, from the real animation rig.
await call('navigate_page',{pageId,url:'file://'+path.join(root,'index.html'),type:'url'});
- for(const kind of ['wally','pippa']){
+ for(const kind of ['wallo','pippa']){
const r=await call('evaluate_script',{pageId,function:'() => ({png:window.exportCharacter('+JSON.stringify(kind)+')})',filePath:path.join(root,'verification','mcp-'+kind+'-export.json')});
const exported=fs.readFileSync(path.join(root,'verification','mcp-'+kind+'-export.json'),'utf8');
const match=exported.match(/data:image\/png;base64,([A-Za-z0-9+/=]+)/);assert(match);fs.writeFileSync(path.join(root,'assets',kind+'.png'),Buffer.from(match[1],'base64'));
diff --git a/scripts/production.cjs b/scripts/production.cjs
index 70ec8b6..c85dfcc 100644
--- a/scripts/production.cjs
+++ b/scripts/production.cjs
@@ -1,4 +1,4 @@
-// Bounded local production and verification of the three Wally & Pippa shorts.
+// Bounded local production and verification of the three Wallo & Pippa shorts.
const fs=require('node:fs');
const path=require('node:path');
const assert=require('node:assert/strict');
@@ -41,7 +41,7 @@ function exec(cmd,args,log){const r=spawnSync(cmd,args,{cwd:root,encoding:'utf8'
await page.evaluate(()=>{window.__timelines.main.seek(3,false);});await page.evaluate(()=>{window.__timelines.main.seek(8,false);});const second=await page.locator('#stage').screenshot();assert(first.equals(second));
checks.push({name:slugs[ep]+' backward seek determinism',verdict:'PASS'});
}
- for(const kind of ['wally','pippa']){const url=await page.evaluate(kind=>window.exportCharacter(kind),kind);fs.writeFileSync(path.join(root,'assets',kind+'.png'),Buffer.from(url.split(',')[1],'base64'));}
+ for(const kind of ['wallo','pippa']){const url=await page.evaluate(kind=>window.exportCharacter(kind),kind);fs.writeFileSync(path.join(root,'assets',kind+'.png'),Buffer.from(url.split(',')[1],'base64'));}
// Contact sheet is a browser-native display of authored frames, preserving assets.
await page.setViewportSize({width:1440,height:1330});await page.setContent('<html><body style="margin:0;background:#243b42"><div style="display:grid;grid-template-columns:repeat(6,240px)">'+slugs.flatMap(slug=>[1,5.5,8,12.8,16,19].map(t=>'<div><img style="width:240px;display:block" src="file://'+path.join(out,slug+'-'+t+'.png')+'"><div style="font:16px monospace;color:#fff7e8;text-align:center">'+slug.slice(0,2)+' / '+t+'s</div></div>')).join('')+'</div></body></html>');
await page.evaluate(()=>Promise.all([...document.images].map(i=>i.decode())));await page.screenshot({path:path.join(out,'contact-sheet.png'),fullPage:true});
@@ -53,12 +53,14 @@ function exec(cmd,args,log){const r=spawnSync(cmd,args,{cwd:root,encoding:'utf8'
assert.equal(video.width,1080);assert.equal(video.height,1920);assert.equal(video.r_frame_rate,'30/1');assert(Math.abs(Number(probe.format.duration)-20)<.08);assert(audio);assert.equal(Number(video.nb_frames),600);
exec('ffmpeg',['-v','error','-i',file,'-f','null','-'],slug+'-decode.txt');
await page.goto('file://'+path.join(root,'watch.html'));
+ assert.equal(await page.locator('h1').textContent(),'Wallo & Pippa.');
+ assert.equal(await page.locator('.cast img').first().getAttribute('src'),'assets/wallo.png');
const v=page.locator('video[data-slug="'+slug+'"]');
await v.evaluate(async v=>{v.muted=true;await v.play();});
await page.waitForFunction(slug=>document.querySelector('video[data-slug="'+slug+'"]').currentTime>.4,slug,{timeout:15000});
const advancing=await v.evaluate(v=>v.currentTime);assert(advancing>.4);await v.evaluate(v=>v.pause());
for(const t of [1,8,13,19]){await v.evaluate((v,t)=>new Promise(resolve=>{v.addEventListener('seeked',resolve,{once:true});v.currentTime=t;}),t);await v.screenshot({path:path.join(out,slug+'-mp4-'+t+'.png')});}
- const playback=await v.evaluate(v=>({duration:v.duration,width:v.videoWidth,height:v.videoHeight,error:v.error?.message||null}));assert.equal(playback.error,null);checks.push({name:slug+' delivered file, full decode and real browser playback',verdict:'PASS',file,bytes:fs.statSync(file).size,frames:video.nb_frames,duration:probe.format.duration,audio:audio.codec_name,playback});
+ const playback=await v.evaluate(v=>({duration:v.duration,width:v.videoWidth,height:v.videoHeight,error:v.error?.message||null}));assert.equal(playback.error,null);checks.push({name:slug+' delivered file, full decode and real browser playback',verdict:'PASS',file,bytes:fs.statSync(file).size,frames:video.nb_frames,duration:probe.format.duration,audio:audio.codec_name,playback,characterName:'Wallo'});
}
} else throw new Error('Unknown phase: '+phase);
assert.deepEqual(errors,[]);checks.push({name:'No browser JavaScript errors',verdict:'PASS'});
diff --git a/snapshots/frame-00-at-1.1s.png b/snapshots/frame-00-at-1.1s.png
index 153c517..9b24b89 100644
Binary files a/snapshots/frame-00-at-1.1s.png and b/snapshots/frame-00-at-1.1s.png differ
diff --git a/snapshots/frame-01-at-5.6s.png b/snapshots/frame-01-at-5.6s.png
index 43bf88f..594ca91 100644
Binary files a/snapshots/frame-01-at-5.6s.png and b/snapshots/frame-01-at-5.6s.png differ
diff --git a/snapshots/frame-02-at-10.0s.png b/snapshots/frame-02-at-10.0s.png
index fe58dc7..28fec5d 100644
Binary files a/snapshots/frame-02-at-10.0s.png and b/snapshots/frame-02-at-10.0s.png differ
diff --git a/snapshots/frame-03-at-14.4s.png b/snapshots/frame-03-at-14.4s.png
index d8812e2..1155071 100644
Binary files a/snapshots/frame-03-at-14.4s.png and b/snapshots/frame-03-at-14.4s.png differ
diff --git a/snapshots/frame-04-at-18.9s.png b/snapshots/frame-04-at-18.9s.png
index fe60bc6..189b195 100644
Binary files a/snapshots/frame-04-at-18.9s.png and b/snapshots/frame-04-at-18.9s.png differ
diff --git a/verification/01-runaway-roll-1.png b/verification/01-runaway-roll-1.png
index 05e2e41..9304980 100644
Binary files a/verification/01-runaway-roll-1.png and b/verification/01-runaway-roll-1.png differ
diff --git a/verification/01-runaway-roll-12.8.png b/verification/01-runaway-roll-12.8.png
index fdb1c06..cdf0ab5 100644
Binary files a/verification/01-runaway-roll-12.8.png and b/verification/01-runaway-roll-12.8.png differ
diff --git a/verification/01-runaway-roll-16.png b/verification/01-runaway-roll-16.png
index efcf602..5bdbfd0 100644
Binary files a/verification/01-runaway-roll-16.png and b/verification/01-runaway-roll-16.png differ
diff --git a/verification/01-runaway-roll-19.png b/verification/01-runaway-roll-19.png
index ff8fada..885ff7a 100644
Binary files a/verification/01-runaway-roll-19.png and b/verification/01-runaway-roll-19.png differ
diff --git a/verification/01-runaway-roll-5.5.png b/verification/01-runaway-roll-5.5.png
index f278127..883f7fe 100644
Binary files a/verification/01-runaway-roll-5.5.png and b/verification/01-runaway-roll-5.5.png differ
diff --git a/verification/01-runaway-roll-8.png b/verification/01-runaway-roll-8.png
index feadaeb..1beea6d 100644
Binary files a/verification/01-runaway-roll-8.png and b/verification/01-runaway-roll-8.png differ
diff --git a/verification/01-runaway-roll-audio.txt b/verification/01-runaway-roll-audio.txt
index 40a4e8a..9e168fc 100644
--- a/verification/01-runaway-roll-audio.txt
+++ b/verification/01-runaway-roll-audio.txt
@@ -1,4 +1,4 @@
-Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/Users/macstudio3/Projects/wallpaper-paint-antics/renders/01-runaway-roll.mp4':
+Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'renders/01-runaway-roll.mp4':
Metadata:
minor_version : 512
major_brand : isom
@@ -6,15 +6,15 @@ Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/Users/macstudio3/Projects/wallpaper-pa
hyperframes_version: 0.0.0-dev
hyperframes_renderer: hyperframes
encoder : Lavf62.12.102
- Duration: 00:00:20.00, start: 0.000000, bitrate: 6051 kb/s
- Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1080x1920 [SAR 1:1 DAR 9:16], 5887 kb/s, 30 fps, 30 tbr, 15360 tbn (default)
+ Duration: 00:00:20.00, start: 0.000000, bitrate: 6054 kb/s
+ Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1080x1920 [SAR 1:1 DAR 9:16], 5890 kb/s, 30 fps, 30 tbr, 15360 tbn (default)
Metadata:
handler_name : VideoHandler
encoder : Lavc62.28.102 libx264
Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 156 kb/s (default)
Metadata:
handler_name : SoundHandler
-[Parsed_volumedetect_0 @ 0x796c186c0] n_samples: 0
+[Parsed_volumedetect_0 @ 0x7e6c08b40] n_samples: 0
Stream mapping:
Stream #0:1 -> #0:0 (aac (native) -> pcm_s16le (native))
Press [q] to stop, [?] for help
@@ -30,13 +30,13 @@ Output #0, null, to 'pipe:':
Metadata:
encoder : Lavc62.28.102 pcm_s16le
handler_name : SoundHandler
-[Parsed_volumedetect_0 @ 0x796c18b40] n_samples: 1921024
-[Parsed_volumedetect_0 @ 0x796c18b40] mean_volume: -25.8 dB
-[Parsed_volumedetect_0 @ 0x796c18b40] max_volume: -8.3 dB
-[Parsed_volumedetect_0 @ 0x796c18b40] histogram_8db: 56
-[Parsed_volumedetect_0 @ 0x796c18b40] histogram_9db: 158
-[Parsed_volumedetect_0 @ 0x796c18b40] histogram_10db: 472
-[Parsed_volumedetect_0 @ 0x796c18b40] histogram_11db: 1224
-[Parsed_volumedetect_0 @ 0x796c18b40] histogram_12db: 2806
-[out#0/null @ 0x796c183c0] video:0KiB audio:3752KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: unknown
-size=N/A time=00:00:20.01 bitrate=N/A speed=1.19e+03x elapsed=0:00:00.01
+[Parsed_volumedetect_0 @ 0x7e6c08fc0] n_samples: 1921024
+[Parsed_volumedetect_0 @ 0x7e6c08fc0] mean_volume: -25.8 dB
+[Parsed_volumedetect_0 @ 0x7e6c08fc0] max_volume: -8.3 dB
+[Parsed_volumedetect_0 @ 0x7e6c08fc0] histogram_8db: 56
+[Parsed_volumedetect_0 @ 0x7e6c08fc0] histogram_9db: 158
+[Parsed_volumedetect_0 @ 0x7e6c08fc0] histogram_10db: 472
+[Parsed_volumedetect_0 @ 0x7e6c08fc0] histogram_11db: 1224
+[Parsed_volumedetect_0 @ 0x7e6c08fc0] histogram_12db: 2806
+[out#0/null @ 0x7e6c08840] video:0KiB audio:3752KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: unknown
+size=N/A time=00:00:20.01 bitrate=N/A speed=1.35e+03x elapsed=0:00:00.01
diff --git a/verification/01-runaway-roll-framemd5.txt b/verification/01-runaway-roll-framemd5.txt
index 1d1fbc7..cc2ae42 100644
--- a/verification/01-runaway-roll-framemd5.txt
+++ b/verification/01-runaway-roll-framemd5.txt
@@ -8,23 +8,23 @@
#dimensions 0: 108x192
#sar 0: 1/1
#stream#, dts, pts, duration, size, hash
-0, 0, 0, 1, 31104, 49cd388e6f53d3470dc42157692388b1
-0, 1, 1, 1, 31104, 45251a14bb0c07572153f07ce98cf6e0
-0, 2, 2, 1, 31104, 1588db700720e2bf19d97fb218cf4935
-0, 3, 3, 1, 31104, abe2614297dee6abb75d4768fd062dd8
-0, 4, 4, 1, 31104, f3c79245ca0d8379eb2a1b56e14b4b5e
-0, 5, 5, 1, 31104, bf4ed434c79676d8673e379a88244466
-0, 6, 6, 1, 31104, 543f8542d4ea6a259e58b549c053101c
-0, 7, 7, 1, 31104, a6818540010e3c2b4a5ff3dcefa84f4a
-0, 8, 8, 1, 31104, 96cc05615fe7bd3efd5a2481b7b5af5d
-0, 9, 9, 1, 31104, 989da2ce162598f3291b3df2e226499e
-0, 10, 10, 1, 31104, 583205eea5d6139ce8490d00b462ac15
-0, 11, 11, 1, 31104, 5a4ac76b87a68acb447e9a5a728e550c
-0, 12, 12, 1, 31104, bb423eb9f9aea7ff50b59708f16cbeb8
-0, 13, 13, 1, 31104, b50163b84f2d9689ee08efaca08f67b4
-0, 14, 14, 1, 31104, 84357741e04d29a0df08a0f02e25f937
-0, 15, 15, 1, 31104, 6d2f49214ab812eb03239b04cda57cd9
-0, 16, 16, 1, 31104, 4e3f2de526318dfa2b830804948a8972
-0, 17, 17, 1, 31104, 592a64e17aa65e070969d4712609ecab
-0, 18, 18, 1, 31104, 782400d1018c4251743a9cae846d76de
-0, 19, 19, 1, 31104, ad54237fa754bb334c6efaf145c3106e
+0, 0, 0, 1, 31104, 9b62785b6a86f8d08f197719e9415f29
+0, 1, 1, 1, 31104, 7e0e5826c898772f1a2636787ef86816
+0, 2, 2, 1, 31104, 5092a9c0c08e3e9d0b116462485da939
+0, 3, 3, 1, 31104, e6efaadfc5e87a230930e82293c60f14
+0, 4, 4, 1, 31104, 5bbf0fccbc9145a5df4a1ab1fca7faac
+0, 5, 5, 1, 31104, d0b0333f29ddf6d8a7b8b3aaa8b86145
+0, 6, 6, 1, 31104, 3c863dde554c3a31c306de5288df9083
+0, 7, 7, 1, 31104, db336cfe60a616990dd9cf361802ef5a
+0, 8, 8, 1, 31104, ab9177441d6e23ae6340db4b943207a3
+0, 9, 9, 1, 31104, 18b5139f14279c27c65e69b9ddeb2360
+0, 10, 10, 1, 31104, ec0735634ec936e6fbcc709c953f4f15
+0, 11, 11, 1, 31104, ce82bdb5b4989efa97d1ed24623f5a1d
+0, 12, 12, 1, 31104, 3e4f709341d6b9ebcb52a100a7ce2b73
+0, 13, 13, 1, 31104, 6160935ca86ba8a6dc9a8c3195992522
+0, 14, 14, 1, 31104, fff12ae06aa45053f523aa09424ea646
+0, 15, 15, 1, 31104, 707831d0eecaef0a03be6292b13cadef
+0, 16, 16, 1, 31104, a2c31aea60459daff5e321aac5330e84
+0, 17, 17, 1, 31104, 7f4c8790ebcd99b2bf0d2c5e7042bfb4
+0, 18, 18, 1, 31104, 79cdeef3f87eb709a4cf0fb4965a9b8f
+0, 19, 19, 1, 31104, 33af73eafec889b708cba2ceab14a452
diff --git a/verification/01-runaway-roll-mp4-1.png b/verification/01-runaway-roll-mp4-1.png
index 0432011..0289f8b 100644
Binary files a/verification/01-runaway-roll-mp4-1.png and b/verification/01-runaway-roll-mp4-1.png differ
diff --git a/verification/01-runaway-roll-mp4-13.png b/verification/01-runaway-roll-mp4-13.png
index 5e7162c..2a793ce 100644
Binary files a/verification/01-runaway-roll-mp4-13.png and b/verification/01-runaway-roll-mp4-13.png differ
diff --git a/verification/01-runaway-roll-mp4-19.png b/verification/01-runaway-roll-mp4-19.png
index a0f5033..9932b13 100644
Binary files a/verification/01-runaway-roll-mp4-19.png and b/verification/01-runaway-roll-mp4-19.png differ
diff --git a/verification/01-runaway-roll-mp4-8.png b/verification/01-runaway-roll-mp4-8.png
index 58d495f..fdc4de6 100644
Binary files a/verification/01-runaway-roll-mp4-8.png and b/verification/01-runaway-roll-mp4-8.png differ
diff --git a/verification/01-runaway-roll-render.txt b/verification/01-runaway-roll-render.txt
index 61a504e..3b8af50 100644
--- a/verification/01-runaway-roll-render.txt
+++ b/verification/01-runaway-roll-render.txt
@@ -20,20 +20,20 @@
[initSession:screenshot] page.goto start (0ms)
[HyperFrames] render runtime fps [object Object]
[HyperFrames] render runtime fps [object Object]
-[initSession:screenshot] page.goto complete (105ms)
-[initSession:screenshot] page.goto complete (105ms)
-[initSession:screenshot] GSAP proxy flush complete (138ms)
-[initSession:screenshot] GSAP proxy flush complete (138ms)
-[initSession:screenshot] pollHfReady complete (140ms)
-[initSession:screenshot] pollHfReady complete (141ms)
-[initSession:screenshot] pollSubCompositionTimelines complete (ready) (142ms)
-[initSession:screenshot] applyVideoMetadataHints complete (142ms)
-[initSession:screenshot] pollSubCompositionTimelines complete (ready) (143ms)
-[initSession:screenshot] applyVideoMetadataHints complete (143ms)
-[initSession:screenshot] media + fonts + tailwind ready (143ms)
-[initSession:screenshot] media + fonts + tailwind ready (144ms)
-[initSession:screenshot] static-frame dedup: disabled (canvas/webgl) (147ms)
-[initSession:screenshot] static-frame dedup: disabled (canvas/webgl) (148ms)
+[initSession:screenshot] page.goto complete (139ms)
+[initSession:screenshot] page.goto complete (142ms)
+[initSession:screenshot] GSAP proxy flush complete (171ms)
+[initSession:screenshot] GSAP proxy flush complete (172ms)
+[initSession:screenshot] pollHfReady complete (175ms)
+[initSession:screenshot] pollHfReady complete (176ms)
+[initSession:screenshot] pollSubCompositionTimelines complete (ready) (178ms)
+[initSession:screenshot] applyVideoMetadataHints complete (178ms)
+[initSession:screenshot] pollSubCompositionTimelines complete (ready) (178ms)
+[initSession:screenshot] applyVideoMetadataHints complete (178ms)
+[initSession:screenshot] media + fonts + tailwind ready (180ms)
+[initSession:screenshot] media + fonts + tailwind ready (179ms)
+[initSession:screenshot] static-frame dedup: disabled (canvas/webgl) (183ms)
+[initSession:screenshot] static-frame dedup: disabled (canvas/webgl) (184ms)
██████░░░░░░░░░░░░░░░░░░░ 27% Capturing frame 30/600 (2 workers)
███████░░░░░░░░░░░░░░░░░░ 30% Capturing frame 60/600 (2 workers)
████████░░░░░░░░░░░░░░░░░ 32% Capturing frame 90/600 (2 workers)
@@ -59,39 +59,38 @@
█████████████████████████ 100% Render complete
◇ /Users/macstudio3/Projects/wallpaper-paint-antics/renders/01-runaway-roll.mp4
- 14.4 MB · 20.0s video · rendered in 19.1s
- [hyperframes] Agent feedback: hyperframes feedback --rating <0-10> --comment "..."
+ 14.4 MB · 20.0s video · rendered in 20.1s
-[INFO] [Render] Pipeline started {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","platform":"darwin","arch":"arm64","nodeVersion":"v26.4.0","fps":{"num":30,"den":1},"format":"mp4","quality":"high","browserGpuMode":"auto","forceScreenshot":false,"protocolTimeout":300000,"browserTimeout":120000,"pageNavigationTimeout":60000,"playerReadyTimeout":45000}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"pipeline","status":"checkpoint","elapsedMs":1,"message":"started","format":"mp4","quality":"high","browserGpuMode":"auto","forceScreenshot":false,"protocolTimeoutMs":300000,"pageNavigationTimeoutMs":60000,"playerReadyTimeoutMs":45000,"requestedWorkers":2}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"compile","status":"start","elapsedMs":2,"needsAlpha":false}
+[INFO] [Render] Pipeline started {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","platform":"darwin","arch":"arm64","nodeVersion":"v26.4.0","fps":{"num":30,"den":1},"format":"mp4","quality":"high","browserGpuMode":"auto","forceScreenshot":false,"protocolTimeout":300000,"browserTimeout":120000,"pageNavigationTimeout":60000,"playerReadyTimeout":45000}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"pipeline","status":"checkpoint","elapsedMs":1,"message":"started","format":"mp4","quality":"high","browserGpuMode":"auto","forceScreenshot":false,"protocolTimeoutMs":300000,"pageNavigationTimeoutMs":60000,"playerReadyTimeoutMs":45000,"requestedWorkers":2}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"compile","status":"start","elapsedMs":2,"needsAlpha":false}
[INFO] [Compiler] Embedded local font file: assets/archivo.ttf (86 KB → data URI)
[INFO] [Compiler] Embedded local font file: assets/space-mono.ttf (79 KB → data URI)
-[INFO] Compiled composition metadata {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","entryFile":"episodes/01-runaway-roll.html","staticDuration":20,"width":1080,"height":1920,"videoCount":0,"audioCount":1,"renderModeHints":{"recommendScreenshot":false,"reasons":[]}}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"compile","status":"end","elapsedMs":359,"durationMs":357,"needsAlpha":false}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"compile","status":"checkpoint","elapsedMs":359,"message":"composition metadata resolved","width":1080,"height":1920,"videoCount":0,"audioCount":1,"imageCount":0,"deviceScaleFactor":1,"forceScreenshot":false,"compositionHash":"882289b0d5df8d77"}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"browser_probe","status":"start","elapsedMs":359,"forceScreenshot":false,"stagePhase":"calibrating"}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"browser_probe","status":"end","elapsedMs":361,"durationMs":2,"forceScreenshot":false,"stagePhase":"calibrating"}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"browser_probe","status":"checkpoint","elapsedMs":361,"message":"duration resolved","durationSeconds":20,"totalFrames":600,"compositionHash":"882289b0d5df8d77","beginFrameStalled":false}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"video_extract","status":"start","elapsedMs":361,"videoCount":0}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"video_extract","status":"end","elapsedMs":362,"durationMs":1,"videoCount":0}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"video_extract","status":"checkpoint","elapsedMs":362,"message":"frames resolved","videoCount":0,"extractedVideoCount":0,"totalFramesExtracted":0,"maxFramesPerVideo":0,"avgFramesPerExtractedVideo":null,"vfrPreflightCount":null,"vfrPreflightMs":null,"cacheHits":null,"cacheMisses":null,"transientRetries":null,"minVideoFrameCoverageRatio":null,"authoredTimedClipCount":3}
-[INFO] [Render] No HDR sources detected — rendering SDR {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775"}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"hdr_detection","status":"checkpoint","elapsedMs":362,"message":"resolved","requestedHdrMode":"auto","effectiveHdr":"sdr","nativeHdrVideoCount":0,"nativeHdrImageCount":0}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"audio_process","status":"start","elapsedMs":362,"audioCount":1}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"audio_process","status":"end","elapsedMs":1137,"durationMs":775,"audioCount":1}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"file_server","status":"start","elapsedMs":1137,"reused":false}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"file_server","status":"end","elapsedMs":1141,"durationMs":4}
+[INFO] Compiled composition metadata {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","entryFile":"episodes/01-runaway-roll.html","staticDuration":20,"width":1080,"height":1920,"videoCount":0,"audioCount":1,"renderModeHints":{"recommendScreenshot":false,"reasons":[]}}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"compile","status":"end","elapsedMs":82,"durationMs":80,"needsAlpha":false}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"compile","status":"checkpoint","elapsedMs":82,"message":"composition metadata resolved","width":1080,"height":1920,"videoCount":0,"audioCount":1,"imageCount":0,"deviceScaleFactor":1,"forceScreenshot":false,"compositionHash":"1d138f1303389a97"}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"browser_probe","status":"start","elapsedMs":82,"forceScreenshot":false,"stagePhase":"calibrating"}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"browser_probe","status":"end","elapsedMs":84,"durationMs":2,"forceScreenshot":false,"stagePhase":"calibrating"}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"browser_probe","status":"checkpoint","elapsedMs":84,"message":"duration resolved","durationSeconds":20,"totalFrames":600,"compositionHash":"1d138f1303389a97","beginFrameStalled":false}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"video_extract","status":"start","elapsedMs":84,"videoCount":0}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"video_extract","status":"end","elapsedMs":85,"durationMs":1,"videoCount":0}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"video_extract","status":"checkpoint","elapsedMs":85,"message":"frames resolved","videoCount":0,"extractedVideoCount":0,"totalFramesExtracted":0,"maxFramesPerVideo":0,"avgFramesPerExtractedVideo":null,"vfrPreflightCount":null,"vfrPreflightMs":null,"cacheHits":null,"cacheMisses":null,"transientRetries":null,"minVideoFrameCoverageRatio":null,"authoredTimedClipCount":3}
+[INFO] [Render] No HDR sources detected — rendering SDR {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a"}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"hdr_detection","status":"checkpoint","elapsedMs":85,"message":"resolved","requestedHdrMode":"auto","effectiveHdr":"sdr","nativeHdrVideoCount":0,"nativeHdrImageCount":0}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"audio_process","status":"start","elapsedMs":85,"audioCount":1}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"audio_process","status":"end","elapsedMs":688,"durationMs":603,"audioCount":1}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"file_server","status":"start","elapsedMs":688,"reused":false}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"file_server","status":"end","elapsedMs":692,"durationMs":4}
[hyperframes] browserGpuMode probe → hardware (WebGL renderer vendor="Google Inc. (Apple)" renderer="ANGLE (Apple, ANGLE Metal Renderer: Apple M3 Ultra, Unspecified Version)")
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"capture_calibration","status":"checkpoint","elapsedMs":1332,"message":"skipped","requestedWorkers":2,"totalFrames":600,"htmlInCanvasDetected":false,"lowMemoryMode":false,"deInversionEligible":false,"deParallelRouterEligible":false}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"worker_resolution","status":"checkpoint","elapsedMs":1332,"message":"resolved","workerCount":2}
-[INFO] streaming-encode gate {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","enabled":false,"configFlag":true,"outputFormat":"mp4","workerCount":2,"durationSeconds":20,"maxDurationSeconds":240}
-[INFO] [Render] Fast capture: default-on drawElement disabled for this render — parallel capture has no runtime self-verification. Set PRODUCER_EXPERIMENTAL_FAST_CAPTURE=true to override. {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775"}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"capture_strategy","status":"checkpoint","elapsedMs":1332,"message":"resolved","workerCount":2,"forceScreenshot":false,"captureBeyondViewport":null,"useStreamingEncode":false,"useLayeredComposite":false,"usePageSideCompositing":false,"hasHdrContent":false,"hasShaderTransitions":false,"isPngSequence":false}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"capture_disk","status":"start","elapsedMs":1332,"stagePhase":"capturing","needsAlpha":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":0,"captureMode":"beginframe","captureOperation":"beginFrame"}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"capture_disk","status":"end","elapsedMs":15671,"durationMs":14339,"stagePhase":"capturing","needsAlpha":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"encode","status":"start","elapsedMs":15671,"stagePhase":"capturing","hasAudio":true,"isPngSequence":false,"isGif":false,"chunkedEncode":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"encode","status":"end","elapsedMs":18355,"durationMs":2683,"stagePhase":"capturing","hasAudio":true,"isPngSequence":false,"isGif":false,"chunkedEncode":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"assemble","status":"start","elapsedMs":18356,"stagePhase":"capturing","hasAudio":true,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"assemble","status":"end","elapsedMs":18984,"durationMs":628,"stagePhase":"capturing","hasAudio":true,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
-[INFO] [Render:trace] {"renderJobId":"84e797c0-b19c-49fd-a5ae-9d03014be775","phase":"pipeline","status":"checkpoint","elapsedMs":19021,"message":"artifact validated","totalElapsedMs":19018}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"capture_calibration","status":"checkpoint","elapsedMs":1085,"message":"skipped","requestedWorkers":2,"totalFrames":600,"htmlInCanvasDetected":false,"lowMemoryMode":false,"deInversionEligible":false,"deParallelRouterEligible":false}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"worker_resolution","status":"checkpoint","elapsedMs":1085,"message":"resolved","workerCount":2}
+[INFO] streaming-encode gate {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","enabled":false,"configFlag":true,"outputFormat":"mp4","workerCount":2,"durationSeconds":20,"maxDurationSeconds":240}
+[INFO] [Render] Fast capture: default-on drawElement disabled for this render — parallel capture has no runtime self-verification. Set PRODUCER_EXPERIMENTAL_FAST_CAPTURE=true to override. {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a"}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"capture_strategy","status":"checkpoint","elapsedMs":1086,"message":"resolved","workerCount":2,"forceScreenshot":false,"captureBeyondViewport":null,"useStreamingEncode":false,"useLayeredComposite":false,"usePageSideCompositing":false,"hasHdrContent":false,"hasShaderTransitions":false,"isPngSequence":false}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"capture_disk","status":"start","elapsedMs":1086,"stagePhase":"capturing","needsAlpha":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":0,"captureMode":"beginframe","captureOperation":"beginFrame"}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"capture_disk","status":"end","elapsedMs":16665,"durationMs":15579,"stagePhase":"capturing","needsAlpha":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"encode","status":"start","elapsedMs":16666,"stagePhase":"capturing","hasAudio":true,"isPngSequence":false,"isGif":false,"chunkedEncode":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"encode","status":"end","elapsedMs":19348,"durationMs":2682,"stagePhase":"capturing","hasAudio":true,"isPngSequence":false,"isGif":false,"chunkedEncode":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"assemble","status":"start","elapsedMs":19349,"stagePhase":"capturing","hasAudio":true,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"assemble","status":"end","elapsedMs":19978,"durationMs":629,"stagePhase":"capturing","hasAudio":true,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
+[INFO] [Render:trace] {"renderJobId":"e7fb8ca3-65a8-40ef-a4cd-dfe4bb7f6c8a","phase":"pipeline","status":"checkpoint","elapsedMs":20015,"message":"artifact validated","totalElapsedMs":20012}
diff --git a/verification/02-splash-of-personality-1.png b/verification/02-splash-of-personality-1.png
index 04c856d..2d1893e 100644
Binary files a/verification/02-splash-of-personality-1.png and b/verification/02-splash-of-personality-1.png differ
diff --git a/verification/02-splash-of-personality-12.8.png b/verification/02-splash-of-personality-12.8.png
index 360767c..eaf28a1 100644
Binary files a/verification/02-splash-of-personality-12.8.png and b/verification/02-splash-of-personality-12.8.png differ
diff --git a/verification/02-splash-of-personality-16.png b/verification/02-splash-of-personality-16.png
index 6fc8f4f..2d4d1bf 100644
Binary files a/verification/02-splash-of-personality-16.png and b/verification/02-splash-of-personality-16.png differ
diff --git a/verification/02-splash-of-personality-19.png b/verification/02-splash-of-personality-19.png
index 34b5d59..227c75e 100644
Binary files a/verification/02-splash-of-personality-19.png and b/verification/02-splash-of-personality-19.png differ
diff --git a/verification/02-splash-of-personality-5.5.png b/verification/02-splash-of-personality-5.5.png
index f568907..b94b5eb 100644
Binary files a/verification/02-splash-of-personality-5.5.png and b/verification/02-splash-of-personality-5.5.png differ
diff --git a/verification/02-splash-of-personality-8.png b/verification/02-splash-of-personality-8.png
index 1c66e03..63ca52d 100644
Binary files a/verification/02-splash-of-personality-8.png and b/verification/02-splash-of-personality-8.png differ
diff --git a/verification/02-splash-of-personality-audio.txt b/verification/02-splash-of-personality-audio.txt
index 482c1ec..4e3db70 100644
--- a/verification/02-splash-of-personality-audio.txt
+++ b/verification/02-splash-of-personality-audio.txt
@@ -1,4 +1,4 @@
-Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/Users/macstudio3/Projects/wallpaper-paint-antics/renders/02-splash-of-personality.mp4':
+Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'renders/02-splash-of-personality.mp4':
Metadata:
minor_version : 512
major_brand : isom
@@ -6,15 +6,15 @@ Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/Users/macstudio3/Projects/wallpaper-pa
hyperframes_version: 0.0.0-dev
hyperframes_renderer: hyperframes
encoder : Lavf62.12.102
- Duration: 00:00:20.00, start: 0.000000, bitrate: 5233 kb/s
- Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1080x1920 [SAR 1:1 DAR 9:16], 5068 kb/s, 30 fps, 30 tbr, 15360 tbn (default)
+ Duration: 00:00:20.00, start: 0.000000, bitrate: 5232 kb/s
+ Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1080x1920 [SAR 1:1 DAR 9:16], 5067 kb/s, 30 fps, 30 tbr, 15360 tbn (default)
Metadata:
handler_name : VideoHandler
encoder : Lavc62.28.102 libx264
Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 157 kb/s (default)
Metadata:
handler_name : SoundHandler
-[Parsed_volumedetect_0 @ 0x840c08c00] n_samples: 0
+[Parsed_volumedetect_0 @ 0xbb6c08b40] n_samples: 0
Stream mapping:
Stream #0:1 -> #0:0 (aac (native) -> pcm_s16le (native))
Press [q] to stop, [?] for help
@@ -30,16 +30,16 @@ Output #0, null, to 'pipe:':
Metadata:
encoder : Lavc62.28.102 pcm_s16le
handler_name : SoundHandler
-[Parsed_volumedetect_0 @ 0x840c09080] n_samples: 1921024
-[Parsed_volumedetect_0 @ 0x840c09080] mean_volume: -26.8 dB
-[Parsed_volumedetect_0 @ 0x840c09080] max_volume: -4.7 dB
-[Parsed_volumedetect_0 @ 0x840c09080] histogram_4db: 14
-[Parsed_volumedetect_0 @ 0x840c09080] histogram_5db: 48
-[Parsed_volumedetect_0 @ 0x840c09080] histogram_6db: 102
-[Parsed_volumedetect_0 @ 0x840c09080] histogram_7db: 164
-[Parsed_volumedetect_0 @ 0x840c09080] histogram_8db: 274
-[Parsed_volumedetect_0 @ 0x840c09080] histogram_9db: 422
-[Parsed_volumedetect_0 @ 0x840c09080] histogram_10db: 598
-[Parsed_volumedetect_0 @ 0x840c09080] histogram_11db: 1073
-[out#0/null @ 0x840c08900] video:0KiB audio:3752KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: unknown
-size=N/A time=00:00:20.01 bitrate=N/A speed=1.25e+03x elapsed=0:00:00.01
+[Parsed_volumedetect_0 @ 0xbb6c08fc0] n_samples: 1921024
+[Parsed_volumedetect_0 @ 0xbb6c08fc0] mean_volume: -26.8 dB
+[Parsed_volumedetect_0 @ 0xbb6c08fc0] max_volume: -4.7 dB
+[Parsed_volumedetect_0 @ 0xbb6c08fc0] histogram_4db: 14
+[Parsed_volumedetect_0 @ 0xbb6c08fc0] histogram_5db: 48
+[Parsed_volumedetect_0 @ 0xbb6c08fc0] histogram_6db: 102
+[Parsed_volumedetect_0 @ 0xbb6c08fc0] histogram_7db: 164
+[Parsed_volumedetect_0 @ 0xbb6c08fc0] histogram_8db: 274
+[Parsed_volumedetect_0 @ 0xbb6c08fc0] histogram_9db: 422
+[Parsed_volumedetect_0 @ 0xbb6c08fc0] histogram_10db: 598
+[Parsed_volumedetect_0 @ 0xbb6c08fc0] histogram_11db: 1073
+[out#0/null @ 0xbb6c08840] video:0KiB audio:3752KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: unknown
+size=N/A time=00:00:20.01 bitrate=N/A speed=1.46e+03x elapsed=0:00:00.01
diff --git a/verification/02-splash-of-personality-framemd5.txt b/verification/02-splash-of-personality-framemd5.txt
index 44ff545..3a0e455 100644
--- a/verification/02-splash-of-personality-framemd5.txt
+++ b/verification/02-splash-of-personality-framemd5.txt
@@ -8,23 +8,23 @@
#dimensions 0: 108x192
#sar 0: 1/1
#stream#, dts, pts, duration, size, hash
-0, 0, 0, 1, 31104, bd10bdb977acb985ac843ef102bf8490
-0, 1, 1, 1, 31104, a02f2e664dadab802d8ad6406c858f6c
-0, 2, 2, 1, 31104, 1a9d3bb40aef98fe0e2d95d481e37848
-0, 3, 3, 1, 31104, cb8f5f2804bcf543eeee3e3e50f7612e
-0, 4, 4, 1, 31104, 71fe72fa07b0f81815ebf5e698c2d031
-0, 5, 5, 1, 31104, 688c0bfd01ef2b6a3c1519c83174bfea
-0, 6, 6, 1, 31104, f5934ba15d56e9b4311c7878790634a0
-0, 7, 7, 1, 31104, 4e95da866bb0e1f7630ef877a3b20d0a
-0, 8, 8, 1, 31104, a21942f53da67ef3336a632a15417537
-0, 9, 9, 1, 31104, c7582932ee35771df1a3dd945bde6978
-0, 10, 10, 1, 31104, cab59a844a896bac93df884ff2dbeb13
-0, 11, 11, 1, 31104, b6c042b875afd093746f263052b800db
-0, 12, 12, 1, 31104, e0fd96eb4a2199e9a719283cba89c81d
-0, 13, 13, 1, 31104, 2d917861a72fc71e55b84677f625befa
-0, 14, 14, 1, 31104, 834deada36ee29cdbcc00ad1f71f1fcf
-0, 15, 15, 1, 31104, e62e862d4e3319804c2a1f66f78b1131
-0, 16, 16, 1, 31104, a2d94ac1bb606764ba5a3660cea64961
-0, 17, 17, 1, 31104, f996e8d9e5403dd16697929ef5a6730c
-0, 18, 18, 1, 31104, 96f567d92e8c9ea1036a26cecab03076
-0, 19, 19, 1, 31104, 2fc07d8affc6b1d3f9f5c89b097254d1
+0, 0, 0, 1, 31104, 6cfb3c4eaa6a748cdc74dd57fcbad00e
+0, 1, 1, 1, 31104, 6f1d776751d8b4c300a02066a5a61054
+0, 2, 2, 1, 31104, b4689fbb0c1b1300aaa1b93f2b264724
+0, 3, 3, 1, 31104, 1dce9156ef55a1d84bad016d52676aaa
+0, 4, 4, 1, 31104, 1f9d1374ad61d8bfd33ba02a6b82069d
+0, 5, 5, 1, 31104, 8c53bd68e0454e0fcea60ecdfdf26ed0
+0, 6, 6, 1, 31104, 068ed853501793f2084140de31f125ca
+0, 7, 7, 1, 31104, cfb39c9588300fd78d021cd459176dba
+0, 8, 8, 1, 31104, db1a8d43f570583645193df464c8fbfa
+0, 9, 9, 1, 31104, 8aa52c055d6773c577a4945f64e9734d
+0, 10, 10, 1, 31104, fba0ae00af0990cde29530114a525d21
+0, 11, 11, 1, 31104, ba53c8ed93692573be79b806b7a01962
+0, 12, 12, 1, 31104, ac21d62fc01dadd7262d90fbd6a1df78
+0, 13, 13, 1, 31104, c3559bf03bf2fbcea249ba4a2cefeec6
+0, 14, 14, 1, 31104, aaa0c391f6496b125c024670fa3df987
+0, 15, 15, 1, 31104, 43bd4e2c8adf6fe03f198c9471297cba
+0, 16, 16, 1, 31104, f52af90d4530f80af400e74a538511cb
+0, 17, 17, 1, 31104, 26ecabdd2ab24fb81e64bbd345594519
+0, 18, 18, 1, 31104, ea04eb70d89f17a77e9ef3c73d361cd3
+0, 19, 19, 1, 31104, 7bf381a8adb3cd0ed7c651c2fbeb2bc5
diff --git a/verification/02-splash-of-personality-mp4-1.png b/verification/02-splash-of-personality-mp4-1.png
index b7dd918..5adb11f 100644
Binary files a/verification/02-splash-of-personality-mp4-1.png and b/verification/02-splash-of-personality-mp4-1.png differ
diff --git a/verification/02-splash-of-personality-mp4-13.png b/verification/02-splash-of-personality-mp4-13.png
index 51774e5..d229c9e 100644
Binary files a/verification/02-splash-of-personality-mp4-13.png and b/verification/02-splash-of-personality-mp4-13.png differ
diff --git a/verification/02-splash-of-personality-mp4-19.png b/verification/02-splash-of-personality-mp4-19.png
index a3f2e0b..259d285 100644
Binary files a/verification/02-splash-of-personality-mp4-19.png and b/verification/02-splash-of-personality-mp4-19.png differ
diff --git a/verification/02-splash-of-personality-mp4-8.png b/verification/02-splash-of-personality-mp4-8.png
index 0d3d08e..4b41e8e 100644
Binary files a/verification/02-splash-of-personality-mp4-8.png and b/verification/02-splash-of-personality-mp4-8.png differ
diff --git a/verification/02-splash-of-personality-render.txt b/verification/02-splash-of-personality-render.txt
index d472161..1333884 100644
--- a/verification/02-splash-of-personality-render.txt
+++ b/verification/02-splash-of-personality-render.txt
@@ -20,20 +20,20 @@
[initSession:screenshot] page.goto start (0ms)
[HyperFrames] render runtime fps [object Object]
[HyperFrames] render runtime fps [object Object]
-[initSession:screenshot] page.goto complete (102ms)
-[initSession:screenshot] page.goto complete (102ms)
-[initSession:screenshot] GSAP proxy flush complete (134ms)
-[initSession:screenshot] GSAP proxy flush complete (133ms)
-[initSession:screenshot] pollHfReady complete (136ms)
-[initSession:screenshot] pollHfReady complete (136ms)
-[initSession:screenshot] pollSubCompositionTimelines complete (ready) (137ms)
-[initSession:screenshot] applyVideoMetadataHints complete (137ms)
-[initSession:screenshot] pollSubCompositionTimelines complete (ready) (137ms)
-[initSession:screenshot] applyVideoMetadataHints complete (137ms)
-[initSession:screenshot] media + fonts + tailwind ready (139ms)
-[initSession:screenshot] media + fonts + tailwind ready (138ms)
-[initSession:screenshot] static-frame dedup: disabled (canvas/webgl) (142ms)
-[initSession:screenshot] static-frame dedup: disabled (canvas/webgl) (141ms)
+[initSession:screenshot] page.goto complete (90ms)
+[initSession:screenshot] page.goto complete (86ms)
+[initSession:screenshot] GSAP proxy flush complete (123ms)
+[initSession:screenshot] GSAP proxy flush complete (118ms)
+[initSession:screenshot] pollHfReady complete (119ms)
+[initSession:screenshot] pollHfReady complete (124ms)
+[initSession:screenshot] pollSubCompositionTimelines complete (ready) (120ms)
+[initSession:screenshot] applyVideoMetadataHints complete (120ms)
+[initSession:screenshot] pollSubCompositionTimelines complete (ready) (126ms)
+[initSession:screenshot] applyVideoMetadataHints complete (126ms)
+[initSession:screenshot] media + fonts + tailwind ready (122ms)
+[initSession:screenshot] media + fonts + tailwind ready (127ms)
+[initSession:screenshot] static-frame dedup: disabled (canvas/webgl) (125ms)
+[initSession:screenshot] static-frame dedup: disabled (canvas/webgl) (130ms)
██████░░░░░░░░░░░░░░░░░░░ 27% Capturing frame 30/600 (2 workers)
███████░░░░░░░░░░░░░░░░░░ 30% Capturing frame 60/600 (2 workers)
████████░░░░░░░░░░░░░░░░░ 32% Capturing frame 90/600 (2 workers)
@@ -59,38 +59,38 @@
█████████████████████████ 100% Render complete
◇ /Users/macstudio3/Projects/wallpaper-paint-antics/renders/02-splash-of-personality.mp4
- 12.5 MB · 20.0s video · rendered in 18.1s
+ 12.5 MB · 20.0s video · rendered in 17.9s
-[INFO] [Render] Pipeline started {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","platform":"darwin","arch":"arm64","nodeVersion":"v26.4.0","fps":{"num":30,"den":1},"format":"mp4","quality":"high","browserGpuMode":"auto","forceScreenshot":false,"protocolTimeout":300000,"browserTimeout":120000,"pageNavigationTimeout":60000,"playerReadyTimeout":45000}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"pipeline","status":"checkpoint","elapsedMs":1,"message":"started","format":"mp4","quality":"high","browserGpuMode":"auto","forceScreenshot":false,"protocolTimeoutMs":300000,"pageNavigationTimeoutMs":60000,"playerReadyTimeoutMs":45000,"requestedWorkers":2}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"compile","status":"start","elapsedMs":2,"needsAlpha":false}
+[INFO] [Render] Pipeline started {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","platform":"darwin","arch":"arm64","nodeVersion":"v26.4.0","fps":{"num":30,"den":1},"format":"mp4","quality":"high","browserGpuMode":"auto","forceScreenshot":false,"protocolTimeout":300000,"browserTimeout":120000,"pageNavigationTimeout":60000,"playerReadyTimeout":45000}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"pipeline","status":"checkpoint","elapsedMs":2,"message":"started","format":"mp4","quality":"high","browserGpuMode":"auto","forceScreenshot":false,"protocolTimeoutMs":300000,"pageNavigationTimeoutMs":60000,"playerReadyTimeoutMs":45000,"requestedWorkers":2}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"compile","status":"start","elapsedMs":3,"needsAlpha":false}
[INFO] [Compiler] Embedded local font file: assets/archivo.ttf (86 KB → data URI)
[INFO] [Compiler] Embedded local font file: assets/space-mono.ttf (79 KB → data URI)
-[INFO] Compiled composition metadata {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","entryFile":"episodes/02-splash-of-personality.html","staticDuration":20,"width":1080,"height":1920,"videoCount":0,"audioCount":1,"renderModeHints":{"recommendScreenshot":false,"reasons":[]}}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"compile","status":"end","elapsedMs":72,"durationMs":69,"needsAlpha":false}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"compile","status":"checkpoint","elapsedMs":73,"message":"composition metadata resolved","width":1080,"height":1920,"videoCount":0,"audioCount":1,"imageCount":0,"deviceScaleFactor":1,"forceScreenshot":false,"compositionHash":"ef7b6d83d3f2a1cb"}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"browser_probe","status":"start","elapsedMs":73,"forceScreenshot":false,"stagePhase":"calibrating"}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"browser_probe","status":"end","elapsedMs":75,"durationMs":2,"forceScreenshot":false,"stagePhase":"calibrating"}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"browser_probe","status":"checkpoint","elapsedMs":75,"message":"duration resolved","durationSeconds":20,"totalFrames":600,"compositionHash":"ef7b6d83d3f2a1cb","beginFrameStalled":false}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"video_extract","status":"start","elapsedMs":75,"videoCount":0}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"video_extract","status":"end","elapsedMs":75,"durationMs":0,"videoCount":0}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"video_extract","status":"checkpoint","elapsedMs":76,"message":"frames resolved","videoCount":0,"extractedVideoCount":0,"totalFramesExtracted":0,"maxFramesPerVideo":0,"avgFramesPerExtractedVideo":null,"vfrPreflightCount":null,"vfrPreflightMs":null,"cacheHits":null,"cacheMisses":null,"transientRetries":null,"minVideoFrameCoverageRatio":null,"authoredTimedClipCount":3}
-[INFO] [Render] No HDR sources detected — rendering SDR {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c"}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"hdr_detection","status":"checkpoint","elapsedMs":76,"message":"resolved","requestedHdrMode":"auto","effectiveHdr":"sdr","nativeHdrVideoCount":0,"nativeHdrImageCount":0}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"audio_process","status":"start","elapsedMs":76,"audioCount":1}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"audio_process","status":"end","elapsedMs":637,"durationMs":561,"audioCount":1}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"file_server","status":"start","elapsedMs":637,"reused":false}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"file_server","status":"end","elapsedMs":643,"durationMs":6}
+[INFO] Compiled composition metadata {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","entryFile":"episodes/02-splash-of-personality.html","staticDuration":20,"width":1080,"height":1920,"videoCount":0,"audioCount":1,"renderModeHints":{"recommendScreenshot":false,"reasons":[]}}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"compile","status":"end","elapsedMs":70,"durationMs":67,"needsAlpha":false}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"compile","status":"checkpoint","elapsedMs":71,"message":"composition metadata resolved","width":1080,"height":1920,"videoCount":0,"audioCount":1,"imageCount":0,"deviceScaleFactor":1,"forceScreenshot":false,"compositionHash":"11b39cee495ea01e"}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"browser_probe","status":"start","elapsedMs":71,"forceScreenshot":false,"stagePhase":"calibrating"}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"browser_probe","status":"end","elapsedMs":73,"durationMs":2,"forceScreenshot":false,"stagePhase":"calibrating"}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"browser_probe","status":"checkpoint","elapsedMs":73,"message":"duration resolved","durationSeconds":20,"totalFrames":600,"compositionHash":"11b39cee495ea01e","beginFrameStalled":false}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"video_extract","status":"start","elapsedMs":73,"videoCount":0}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"video_extract","status":"end","elapsedMs":73,"durationMs":0,"videoCount":0}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"video_extract","status":"checkpoint","elapsedMs":74,"message":"frames resolved","videoCount":0,"extractedVideoCount":0,"totalFramesExtracted":0,"maxFramesPerVideo":0,"avgFramesPerExtractedVideo":null,"vfrPreflightCount":null,"vfrPreflightMs":null,"cacheHits":null,"cacheMisses":null,"transientRetries":null,"minVideoFrameCoverageRatio":null,"authoredTimedClipCount":3}
+[INFO] [Render] No HDR sources detected — rendering SDR {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855"}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"hdr_detection","status":"checkpoint","elapsedMs":74,"message":"resolved","requestedHdrMode":"auto","effectiveHdr":"sdr","nativeHdrVideoCount":0,"nativeHdrImageCount":0}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"audio_process","status":"start","elapsedMs":74,"audioCount":1}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"audio_process","status":"end","elapsedMs":643,"durationMs":569,"audioCount":1}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"file_server","status":"start","elapsedMs":643,"reused":false}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"file_server","status":"end","elapsedMs":648,"durationMs":5}
[hyperframes] browserGpuMode probe → hardware (WebGL renderer vendor="Google Inc. (Apple)" renderer="ANGLE (Apple, ANGLE Metal Renderer: Apple M3 Ultra, Unspecified Version)")
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"capture_calibration","status":"checkpoint","elapsedMs":831,"message":"skipped","requestedWorkers":2,"totalFrames":600,"htmlInCanvasDetected":false,"lowMemoryMode":false,"deInversionEligible":false,"deParallelRouterEligible":false}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"worker_resolution","status":"checkpoint","elapsedMs":832,"message":"resolved","workerCount":2}
-[INFO] streaming-encode gate {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","enabled":false,"configFlag":true,"outputFormat":"mp4","workerCount":2,"durationSeconds":20,"maxDurationSeconds":240}
-[INFO] [Render] Fast capture: default-on drawElement disabled for this render — parallel capture has no runtime self-verification. Set PRODUCER_EXPERIMENTAL_FAST_CAPTURE=true to override. {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c"}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"capture_strategy","status":"checkpoint","elapsedMs":832,"message":"resolved","workerCount":2,"forceScreenshot":false,"captureBeyondViewport":null,"useStreamingEncode":false,"useLayeredComposite":false,"usePageSideCompositing":false,"hasHdrContent":false,"hasShaderTransitions":false,"isPngSequence":false}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"capture_disk","status":"start","elapsedMs":832,"stagePhase":"capturing","needsAlpha":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":0,"captureMode":"beginframe","captureOperation":"beginFrame"}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"capture_disk","status":"end","elapsedMs":14733,"durationMs":13901,"stagePhase":"capturing","needsAlpha":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"encode","status":"start","elapsedMs":14734,"stagePhase":"capturing","hasAudio":true,"isPngSequence":false,"isGif":false,"chunkedEncode":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"encode","status":"end","elapsedMs":17429,"durationMs":2695,"stagePhase":"capturing","hasAudio":true,"isPngSequence":false,"isGif":false,"chunkedEncode":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"assemble","status":"start","elapsedMs":17430,"stagePhase":"capturing","hasAudio":true,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"assemble","status":"end","elapsedMs":18045,"durationMs":615,"stagePhase":"capturing","hasAudio":true,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
-[INFO] [Render:trace] {"renderJobId":"3420f2a1-db43-4133-919c-2c2591bce22c","phase":"pipeline","status":"checkpoint","elapsedMs":18085,"message":"artifact validated","totalElapsedMs":18082}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"capture_calibration","status":"checkpoint","elapsedMs":831,"message":"skipped","requestedWorkers":2,"totalFrames":600,"htmlInCanvasDetected":false,"lowMemoryMode":false,"deInversionEligible":false,"deParallelRouterEligible":false}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"worker_resolution","status":"checkpoint","elapsedMs":832,"message":"resolved","workerCount":2}
+[INFO] streaming-encode gate {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","enabled":false,"configFlag":true,"outputFormat":"mp4","workerCount":2,"durationSeconds":20,"maxDurationSeconds":240}
+[INFO] [Render] Fast capture: default-on drawElement disabled for this render — parallel capture has no runtime self-verification. Set PRODUCER_EXPERIMENTAL_FAST_CAPTURE=true to override. {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855"}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"capture_strategy","status":"checkpoint","elapsedMs":832,"message":"resolved","workerCount":2,"forceScreenshot":false,"captureBeyondViewport":null,"useStreamingEncode":false,"useLayeredComposite":false,"usePageSideCompositing":false,"hasHdrContent":false,"hasShaderTransitions":false,"isPngSequence":false}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"capture_disk","status":"start","elapsedMs":832,"stagePhase":"capturing","needsAlpha":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":0,"captureMode":"beginframe","captureOperation":"beginFrame"}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"capture_disk","status":"end","elapsedMs":14455,"durationMs":13623,"stagePhase":"capturing","needsAlpha":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"encode","status":"start","elapsedMs":14455,"stagePhase":"capturing","hasAudio":true,"isPngSequence":false,"isGif":false,"chunkedEncode":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"encode","status":"end","elapsedMs":17154,"durationMs":2699,"stagePhase":"capturing","hasAudio":true,"isPngSequence":false,"isGif":false,"chunkedEncode":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"assemble","status":"start","elapsedMs":17155,"stagePhase":"capturing","hasAudio":true,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"assemble","status":"end","elapsedMs":17764,"durationMs":609,"stagePhase":"capturing","hasAudio":true,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
+[INFO] [Render:trace] {"renderJobId":"5b86cecb-dbb0-4fff-b96a-e2a5224cd855","phase":"pipeline","status":"checkpoint","elapsedMs":17803,"message":"artifact validated","totalElapsedMs":17800}
diff --git a/verification/03-great-wall-off-1.png b/verification/03-great-wall-off-1.png
index 4b304f9..51f6585 100644
Binary files a/verification/03-great-wall-off-1.png and b/verification/03-great-wall-off-1.png differ
diff --git a/verification/03-great-wall-off-12.8.png b/verification/03-great-wall-off-12.8.png
index 1348cb0..7c9fb8c 100644
Binary files a/verification/03-great-wall-off-12.8.png and b/verification/03-great-wall-off-12.8.png differ
diff --git a/verification/03-great-wall-off-16.png b/verification/03-great-wall-off-16.png
index 40b1f8d..6532162 100644
Binary files a/verification/03-great-wall-off-16.png and b/verification/03-great-wall-off-16.png differ
diff --git a/verification/03-great-wall-off-19.png b/verification/03-great-wall-off-19.png
index 3894c1c..52bc151 100644
Binary files a/verification/03-great-wall-off-19.png and b/verification/03-great-wall-off-19.png differ
diff --git a/verification/03-great-wall-off-5.5.png b/verification/03-great-wall-off-5.5.png
index 2a72ea7..0579a84 100644
Binary files a/verification/03-great-wall-off-5.5.png and b/verification/03-great-wall-off-5.5.png differ
diff --git a/verification/03-great-wall-off-8.png b/verification/03-great-wall-off-8.png
index 0c8d1c4..b2bbd57 100644
Binary files a/verification/03-great-wall-off-8.png and b/verification/03-great-wall-off-8.png differ
diff --git a/verification/03-great-wall-off-audio.txt b/verification/03-great-wall-off-audio.txt
index e73d170..954a7f0 100644
--- a/verification/03-great-wall-off-audio.txt
+++ b/verification/03-great-wall-off-audio.txt
@@ -1,4 +1,4 @@
-Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/Users/macstudio3/Projects/wallpaper-paint-antics/renders/03-great-wall-off.mp4':
+Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'renders/03-great-wall-off.mp4':
Metadata:
minor_version : 512
major_brand : isom
@@ -6,15 +6,15 @@ Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/Users/macstudio3/Projects/wallpaper-pa
hyperframes_version: 0.0.0-dev
hyperframes_renderer: hyperframes
encoder : Lavf62.12.102
- Duration: 00:00:20.00, start: 0.000000, bitrate: 6169 kb/s
- Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1080x1920 [SAR 1:1 DAR 9:16], 6003 kb/s, 30 fps, 30 tbr, 15360 tbn (default)
+ Duration: 00:00:20.00, start: 0.000000, bitrate: 6170 kb/s
+ Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1080x1920 [SAR 1:1 DAR 9:16], 6005 kb/s, 30 fps, 30 tbr, 15360 tbn (default)
Metadata:
handler_name : VideoHandler
encoder : Lavc62.28.102 libx264
Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 157 kb/s (default)
Metadata:
handler_name : SoundHandler
-[Parsed_volumedetect_0 @ 0x952c08c00] n_samples: 0
+[Parsed_volumedetect_0 @ 0xad6c38600] n_samples: 0
Stream mapping:
Stream #0:1 -> #0:0 (aac (native) -> pcm_s16le (native))
Press [q] to stop, [?] for help
@@ -30,18 +30,18 @@ Output #0, null, to 'pipe:':
Metadata:
encoder : Lavc62.28.102 pcm_s16le
handler_name : SoundHandler
-[Parsed_volumedetect_0 @ 0x952c09080] n_samples: 1921024
-[Parsed_volumedetect_0 @ 0x952c09080] mean_volume: -27.9 dB
-[Parsed_volumedetect_0 @ 0x952c09080] max_volume: -5.8 dB
-[Parsed_volumedetect_0 @ 0x952c09080] histogram_5db: 4
-[Parsed_volumedetect_0 @ 0x952c09080] histogram_6db: 6
-[Parsed_volumedetect_0 @ 0x952c09080] histogram_7db: 16
-[Parsed_volumedetect_0 @ 0x952c09080] histogram_8db: 44
-[Parsed_volumedetect_0 @ 0x952c09080] histogram_9db: 90
-[Parsed_volumedetect_0 @ 0x952c09080] histogram_10db: 108
-[Parsed_volumedetect_0 @ 0x952c09080] histogram_11db: 156
-[Parsed_volumedetect_0 @ 0x952c09080] histogram_12db: 236
-[Parsed_volumedetect_0 @ 0x952c09080] histogram_13db: 760
-[Parsed_volumedetect_0 @ 0x952c09080] histogram_14db: 1484
-[out#0/null @ 0x952c08900] video:0KiB audio:3752KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: unknown
-size=N/A time=00:00:20.01 bitrate=N/A speed=1.23e+03x elapsed=0:00:00.01
+[Parsed_volumedetect_0 @ 0xad6c38a80] n_samples: 1921024
+[Parsed_volumedetect_0 @ 0xad6c38a80] mean_volume: -27.9 dB
+[Parsed_volumedetect_0 @ 0xad6c38a80] max_volume: -5.8 dB
+[Parsed_volumedetect_0 @ 0xad6c38a80] histogram_5db: 4
+[Parsed_volumedetect_0 @ 0xad6c38a80] histogram_6db: 6
+[Parsed_volumedetect_0 @ 0xad6c38a80] histogram_7db: 16
+[Parsed_volumedetect_0 @ 0xad6c38a80] histogram_8db: 44
+[Parsed_volumedetect_0 @ 0xad6c38a80] histogram_9db: 90
+[Parsed_volumedetect_0 @ 0xad6c38a80] histogram_10db: 108
+[Parsed_volumedetect_0 @ 0xad6c38a80] histogram_11db: 156
+[Parsed_volumedetect_0 @ 0xad6c38a80] histogram_12db: 236
+[Parsed_volumedetect_0 @ 0xad6c38a80] histogram_13db: 760
+[Parsed_volumedetect_0 @ 0xad6c38a80] histogram_14db: 1484
+[out#0/null @ 0xad6c38300] video:0KiB audio:3752KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: unknown
+size=N/A time=00:00:20.01 bitrate=N/A speed=1.41e+03x elapsed=0:00:00.01
diff --git a/verification/03-great-wall-off-framemd5.txt b/verification/03-great-wall-off-framemd5.txt
index 4ccfd47..beb81f6 100644
--- a/verification/03-great-wall-off-framemd5.txt
+++ b/verification/03-great-wall-off-framemd5.txt
@@ -8,23 +8,23 @@
#dimensions 0: 108x192
#sar 0: 1/1
#stream#, dts, pts, duration, size, hash
-0, 0, 0, 1, 31104, 802beb7d729417c619b549e163793375
-0, 1, 1, 1, 31104, 3196d86bc2bd3747da2de44666c92a58
-0, 2, 2, 1, 31104, dbb8176f42fcefa4d0e07b4cd32c61cd
-0, 3, 3, 1, 31104, 93fae62b481ab49fea887fb8d214b243
-0, 4, 4, 1, 31104, dd640db3263c238498c9b89c7aaeef96
-0, 5, 5, 1, 31104, 7b3dc0c26e01335cf4e03f3f8f6be069
-0, 6, 6, 1, 31104, 4ca0051dce81c655d82b217259893d9c
-0, 7, 7, 1, 31104, 9d1520286aa6422f45585bedb79d2d1f
-0, 8, 8, 1, 31104, fa37e0c770064ae252ff76b565c1d277
-0, 9, 9, 1, 31104, 3039eb0d44fc023a15a6f416b32f22da
-0, 10, 10, 1, 31104, 8bc553854d3507b0e53d8573eb2bf6f6
-0, 11, 11, 1, 31104, ba909e37ca3f945b03b88d916483b47b
-0, 12, 12, 1, 31104, a5c965a6f5551c9d5698a28c73932a0a
-0, 13, 13, 1, 31104, 3446a993615781116a34d47da7ac0383
-0, 14, 14, 1, 31104, afbd4e6c1eee8a859ec941e01f012c99
-0, 15, 15, 1, 31104, d1d473c82bc1554e82cd67d2dd7d3af7
-0, 16, 16, 1, 31104, d83c25e396e1ab79c163bc089c077d04
-0, 17, 17, 1, 31104, 777418fb3e690e8cb6290da1feb538fa
-0, 18, 18, 1, 31104, 760ddb421ea26500aea66910b132ac49
-0, 19, 19, 1, 31104, 2cd7dac13610495c178d803353fefa39
+0, 0, 0, 1, 31104, 6ef632e5f0d5346efc09f780290d0f61
+0, 1, 1, 1, 31104, f137c19e3806ee524d9bcc944fe68780
+0, 2, 2, 1, 31104, 752b1c9baefe55ffb3a5984344e34e43
+0, 3, 3, 1, 31104, 39d075b2729e94d844a2a7686b526d1e
+0, 4, 4, 1, 31104, 2ab1be88ac8d6f1425807a70494c1e7c
+0, 5, 5, 1, 31104, 0d8c9693ae2314303c81816774fce196
+0, 6, 6, 1, 31104, 69b690df4f4e7e112ca1046d3c1de290
+0, 7, 7, 1, 31104, e6ff4d1e242b223e221304821894e317
+0, 8, 8, 1, 31104, a8a145fc4b4f534fbe32903004867ba3
+0, 9, 9, 1, 31104, e89fab98b8bc74d9e799f52039de342d
+0, 10, 10, 1, 31104, 85da59505d261055aaff74f8efa366ac
+0, 11, 11, 1, 31104, eae45c53c4bfa731710df440bfac22e1
+0, 12, 12, 1, 31104, 88d1862159a48e100a8d01b1ffb59cf6
+0, 13, 13, 1, 31104, 5893559d30576c49b35db5186b0bfba6
+0, 14, 14, 1, 31104, ae216bc060da59a5121ef8fa4cc4b47a
+0, 15, 15, 1, 31104, 6ff8dcabc4fa0296d5c06586110a6273
+0, 16, 16, 1, 31104, 7444af0697e64c6b06fd94fee0569209
+0, 17, 17, 1, 31104, dedcc3d7390369da730c5667bd191ca6
+0, 18, 18, 1, 31104, 1e3078741d93745fb02a90a810fe78f1
+0, 19, 19, 1, 31104, 0757bbf536e92340776a86ad7823aff3
diff --git a/verification/03-great-wall-off-mp4-1.png b/verification/03-great-wall-off-mp4-1.png
index 578499c..3f14724 100644
Binary files a/verification/03-great-wall-off-mp4-1.png and b/verification/03-great-wall-off-mp4-1.png differ
diff --git a/verification/03-great-wall-off-mp4-13.png b/verification/03-great-wall-off-mp4-13.png
index f3daae2..a53cd53 100644
Binary files a/verification/03-great-wall-off-mp4-13.png and b/verification/03-great-wall-off-mp4-13.png differ
diff --git a/verification/03-great-wall-off-mp4-19.png b/verification/03-great-wall-off-mp4-19.png
index 0d46ad4..f5e1cdb 100644
Binary files a/verification/03-great-wall-off-mp4-19.png and b/verification/03-great-wall-off-mp4-19.png differ
diff --git a/verification/03-great-wall-off-mp4-8.png b/verification/03-great-wall-off-mp4-8.png
index af20a60..425f38b 100644
Binary files a/verification/03-great-wall-off-mp4-8.png and b/verification/03-great-wall-off-mp4-8.png differ
diff --git a/verification/03-great-wall-off-render.txt b/verification/03-great-wall-off-render.txt
index 2288497..145d36d 100644
--- a/verification/03-great-wall-off-render.txt
+++ b/verification/03-great-wall-off-render.txt
@@ -20,20 +20,20 @@
[initSession:screenshot] page.goto start (0ms)
[HyperFrames] render runtime fps [object Object]
[HyperFrames] render runtime fps [object Object]
+[initSession:screenshot] page.goto complete (95ms)
[initSession:screenshot] page.goto complete (100ms)
-[initSession:screenshot] page.goto complete (101ms)
-[initSession:screenshot] GSAP proxy flush complete (131ms)
-[initSession:screenshot] GSAP proxy flush complete (133ms)
-[initSession:screenshot] pollHfReady complete (134ms)
-[initSession:screenshot] pollHfReady complete (134ms)
-[initSession:screenshot] pollSubCompositionTimelines complete (ready) (135ms)
-[initSession:screenshot] applyVideoMetadataHints complete (136ms)
-[initSession:screenshot] pollSubCompositionTimelines complete (ready) (135ms)
-[initSession:screenshot] applyVideoMetadataHints complete (135ms)
-[initSession:screenshot] media + fonts + tailwind ready (137ms)
+[initSession:screenshot] GSAP proxy flush complete (126ms)
+[initSession:screenshot] GSAP proxy flush complete (130ms)
+[initSession:screenshot] pollHfReady complete (132ms)
+[initSession:screenshot] pollHfReady complete (129ms)
+[initSession:screenshot] pollSubCompositionTimelines complete (ready) (134ms)
+[initSession:screenshot] applyVideoMetadataHints complete (134ms)
+[initSession:screenshot] pollSubCompositionTimelines complete (ready) (131ms)
+[initSession:screenshot] applyVideoMetadataHints complete (131ms)
[initSession:screenshot] media + fonts + tailwind ready (136ms)
-[initSession:screenshot] static-frame dedup: disabled (canvas/webgl) (140ms)
+[initSession:screenshot] media + fonts + tailwind ready (132ms)
[initSession:screenshot] static-frame dedup: disabled (canvas/webgl) (139ms)
+[initSession:screenshot] static-frame dedup: disabled (canvas/webgl) (135ms)
██████░░░░░░░░░░░░░░░░░░░ 27% Capturing frame 30/600 (2 workers)
███████░░░░░░░░░░░░░░░░░░ 30% Capturing frame 60/600 (2 workers)
████████░░░░░░░░░░░░░░░░░ 32% Capturing frame 90/600 (2 workers)
@@ -59,38 +59,38 @@
█████████████████████████ 100% Render complete
◇ /Users/macstudio3/Projects/wallpaper-paint-antics/renders/03-great-wall-off.mp4
- 14.7 MB · 20.0s video · rendered in 18.1s
+ 14.7 MB · 20.0s video · rendered in 18.0s
-[INFO] [Render] Pipeline started {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","platform":"darwin","arch":"arm64","nodeVersion":"v26.4.0","fps":{"num":30,"den":1},"format":"mp4","quality":"high","browserGpuMode":"auto","forceScreenshot":false,"protocolTimeout":300000,"browserTimeout":120000,"pageNavigationTimeout":60000,"playerReadyTimeout":45000}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"pipeline","status":"checkpoint","elapsedMs":1,"message":"started","format":"mp4","quality":"high","browserGpuMode":"auto","forceScreenshot":false,"protocolTimeoutMs":300000,"pageNavigationTimeoutMs":60000,"playerReadyTimeoutMs":45000,"requestedWorkers":2}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"compile","status":"start","elapsedMs":2,"needsAlpha":false}
+[INFO] [Render] Pipeline started {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","platform":"darwin","arch":"arm64","nodeVersion":"v26.4.0","fps":{"num":30,"den":1},"format":"mp4","quality":"high","browserGpuMode":"auto","forceScreenshot":false,"protocolTimeout":300000,"browserTimeout":120000,"pageNavigationTimeout":60000,"playerReadyTimeout":45000}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"pipeline","status":"checkpoint","elapsedMs":2,"message":"started","format":"mp4","quality":"high","browserGpuMode":"auto","forceScreenshot":false,"protocolTimeoutMs":300000,"pageNavigationTimeoutMs":60000,"playerReadyTimeoutMs":45000,"requestedWorkers":2}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"compile","status":"start","elapsedMs":3,"needsAlpha":false}
[INFO] [Compiler] Embedded local font file: assets/archivo.ttf (86 KB → data URI)
[INFO] [Compiler] Embedded local font file: assets/space-mono.ttf (79 KB → data URI)
-[INFO] Compiled composition metadata {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","entryFile":"episodes/03-great-wall-off.html","staticDuration":20,"width":1080,"height":1920,"videoCount":0,"audioCount":1,"renderModeHints":{"recommendScreenshot":false,"reasons":[]}}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"compile","status":"end","elapsedMs":71,"durationMs":69,"needsAlpha":false}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"compile","status":"checkpoint","elapsedMs":71,"message":"composition metadata resolved","width":1080,"height":1920,"videoCount":0,"audioCount":1,"imageCount":0,"deviceScaleFactor":1,"forceScreenshot":false,"compositionHash":"84633b9740d3998f"}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"browser_probe","status":"start","elapsedMs":71,"forceScreenshot":false,"stagePhase":"calibrating"}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"browser_probe","status":"end","elapsedMs":73,"durationMs":2,"forceScreenshot":false,"stagePhase":"calibrating"}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"browser_probe","status":"checkpoint","elapsedMs":74,"message":"duration resolved","durationSeconds":20,"totalFrames":600,"compositionHash":"84633b9740d3998f","beginFrameStalled":false}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"video_extract","status":"start","elapsedMs":74,"videoCount":0}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"video_extract","status":"end","elapsedMs":74,"durationMs":0,"videoCount":0}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"video_extract","status":"checkpoint","elapsedMs":74,"message":"frames resolved","videoCount":0,"extractedVideoCount":0,"totalFramesExtracted":0,"maxFramesPerVideo":0,"avgFramesPerExtractedVideo":null,"vfrPreflightCount":null,"vfrPreflightMs":null,"cacheHits":null,"cacheMisses":null,"transientRetries":null,"minVideoFrameCoverageRatio":null,"authoredTimedClipCount":3}
-[INFO] [Render] No HDR sources detected — rendering SDR {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb"}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"hdr_detection","status":"checkpoint","elapsedMs":74,"message":"resolved","requestedHdrMode":"auto","effectiveHdr":"sdr","nativeHdrVideoCount":0,"nativeHdrImageCount":0}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"audio_process","status":"start","elapsedMs":74,"audioCount":1}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"audio_process","status":"end","elapsedMs":660,"durationMs":586,"audioCount":1}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"file_server","status":"start","elapsedMs":660,"reused":false}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"file_server","status":"end","elapsedMs":666,"durationMs":6}
+[INFO] Compiled composition metadata {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","entryFile":"episodes/03-great-wall-off.html","staticDuration":20,"width":1080,"height":1920,"videoCount":0,"audioCount":1,"renderModeHints":{"recommendScreenshot":false,"reasons":[]}}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"compile","status":"end","elapsedMs":71,"durationMs":68,"needsAlpha":false}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"compile","status":"checkpoint","elapsedMs":71,"message":"composition metadata resolved","width":1080,"height":1920,"videoCount":0,"audioCount":1,"imageCount":0,"deviceScaleFactor":1,"forceScreenshot":false,"compositionHash":"95302cd19f5e307f"}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"browser_probe","status":"start","elapsedMs":71,"forceScreenshot":false,"stagePhase":"calibrating"}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"browser_probe","status":"end","elapsedMs":73,"durationMs":1,"forceScreenshot":false,"stagePhase":"calibrating"}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"browser_probe","status":"checkpoint","elapsedMs":74,"message":"duration resolved","durationSeconds":20,"totalFrames":600,"compositionHash":"95302cd19f5e307f","beginFrameStalled":false}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"video_extract","status":"start","elapsedMs":74,"videoCount":0}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"video_extract","status":"end","elapsedMs":74,"durationMs":0,"videoCount":0}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"video_extract","status":"checkpoint","elapsedMs":74,"message":"frames resolved","videoCount":0,"extractedVideoCount":0,"totalFramesExtracted":0,"maxFramesPerVideo":0,"avgFramesPerExtractedVideo":null,"vfrPreflightCount":null,"vfrPreflightMs":null,"cacheHits":null,"cacheMisses":null,"transientRetries":null,"minVideoFrameCoverageRatio":null,"authoredTimedClipCount":3}
+[INFO] [Render] No HDR sources detected — rendering SDR {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed"}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"hdr_detection","status":"checkpoint","elapsedMs":74,"message":"resolved","requestedHdrMode":"auto","effectiveHdr":"sdr","nativeHdrVideoCount":0,"nativeHdrImageCount":0}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"audio_process","status":"start","elapsedMs":74,"audioCount":1}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"audio_process","status":"end","elapsedMs":665,"durationMs":591,"audioCount":1}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"file_server","status":"start","elapsedMs":665,"reused":false}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"file_server","status":"end","elapsedMs":670,"durationMs":5}
[hyperframes] browserGpuMode probe → hardware (WebGL renderer vendor="Google Inc. (Apple)" renderer="ANGLE (Apple, ANGLE Metal Renderer: Apple M3 Ultra, Unspecified Version)")
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"capture_calibration","status":"checkpoint","elapsedMs":849,"message":"skipped","requestedWorkers":2,"totalFrames":600,"htmlInCanvasDetected":false,"lowMemoryMode":false,"deInversionEligible":false,"deParallelRouterEligible":false}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"worker_resolution","status":"checkpoint","elapsedMs":850,"message":"resolved","workerCount":2}
-[INFO] streaming-encode gate {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","enabled":false,"configFlag":true,"outputFormat":"mp4","workerCount":2,"durationSeconds":20,"maxDurationSeconds":240}
-[INFO] [Render] Fast capture: default-on drawElement disabled for this render — parallel capture has no runtime self-verification. Set PRODUCER_EXPERIMENTAL_FAST_CAPTURE=true to override. {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb"}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"capture_strategy","status":"checkpoint","elapsedMs":850,"message":"resolved","workerCount":2,"forceScreenshot":false,"captureBeyondViewport":null,"useStreamingEncode":false,"useLayeredComposite":false,"usePageSideCompositing":false,"hasHdrContent":false,"hasShaderTransitions":false,"isPngSequence":false}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"capture_disk","status":"start","elapsedMs":850,"stagePhase":"capturing","needsAlpha":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":0,"captureMode":"beginframe","captureOperation":"beginFrame"}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"capture_disk","status":"end","elapsedMs":14536,"durationMs":13686,"stagePhase":"capturing","needsAlpha":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"encode","status":"start","elapsedMs":14536,"stagePhase":"capturing","hasAudio":true,"isPngSequence":false,"isGif":false,"chunkedEncode":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"encode","status":"end","elapsedMs":17392,"durationMs":2856,"stagePhase":"capturing","hasAudio":true,"isPngSequence":false,"isGif":false,"chunkedEncode":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"assemble","status":"start","elapsedMs":17392,"stagePhase":"capturing","hasAudio":true,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"assemble","status":"end","elapsedMs":18011,"durationMs":619,"stagePhase":"capturing","hasAudio":true,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
-[INFO] [Render:trace] {"renderJobId":"a58e12d2-7607-41b2-bedf-66eb8b530afb","phase":"pipeline","status":"checkpoint","elapsedMs":18050,"message":"artifact validated","totalElapsedMs":18046}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"capture_calibration","status":"checkpoint","elapsedMs":847,"message":"skipped","requestedWorkers":2,"totalFrames":600,"htmlInCanvasDetected":false,"lowMemoryMode":false,"deInversionEligible":false,"deParallelRouterEligible":false}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"worker_resolution","status":"checkpoint","elapsedMs":847,"message":"resolved","workerCount":2}
+[INFO] streaming-encode gate {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","enabled":false,"configFlag":true,"outputFormat":"mp4","workerCount":2,"durationSeconds":20,"maxDurationSeconds":240}
+[INFO] [Render] Fast capture: default-on drawElement disabled for this render — parallel capture has no runtime self-verification. Set PRODUCER_EXPERIMENTAL_FAST_CAPTURE=true to override. {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed"}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"capture_strategy","status":"checkpoint","elapsedMs":847,"message":"resolved","workerCount":2,"forceScreenshot":false,"captureBeyondViewport":null,"useStreamingEncode":false,"useLayeredComposite":false,"usePageSideCompositing":false,"hasHdrContent":false,"hasShaderTransitions":false,"isPngSequence":false}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"capture_disk","status":"start","elapsedMs":848,"stagePhase":"capturing","needsAlpha":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":0,"captureMode":"beginframe","captureOperation":"beginFrame"}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"capture_disk","status":"end","elapsedMs":14333,"durationMs":13485,"stagePhase":"capturing","needsAlpha":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"encode","status":"start","elapsedMs":14333,"stagePhase":"capturing","hasAudio":true,"isPngSequence":false,"isGif":false,"chunkedEncode":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"encode","status":"end","elapsedMs":17217,"durationMs":2884,"stagePhase":"capturing","hasAudio":true,"isPngSequence":false,"isGif":false,"chunkedEncode":false,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"assemble","status":"start","elapsedMs":17217,"stagePhase":"capturing","hasAudio":true,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"assemble","status":"end","elapsedMs":17870,"durationMs":653,"stagePhase":"capturing","hasAudio":true,"workerCount":2,"forceScreenshot":false,"totalFrames":600,"framesCompleted":600,"captureMode":"beginframe","captureOperation":"encode"}
+[INFO] [Render:trace] {"renderJobId":"3a152efa-d95e-4d5a-b7bc-461699321bed","phase":"pipeline","status":"checkpoint","elapsedMs":17908,"message":"artifact validated","totalElapsedMs":17905}
diff --git a/verification/contact-sheet.png b/verification/contact-sheet.png
index 61edd46..71a029b 100644
Binary files a/verification/contact-sheet.png and b/verification/contact-sheet.png differ
diff --git a/verification/e2e-proof.json b/verification/e2e-proof.json
index 51ee2c5..a066c46 100644
--- a/verification/e2e-proof.json
+++ b/verification/e2e-proof.json
@@ -1,34 +1,31 @@
{
- "intent": "Two original animated human decorators and three finished 20-second comedy videos.",
+ "intent": "Rename the wallpaper installer to Wallo across all character files, review page and three finished 20-second videos.",
"ticket": "TK-11286-create-two-animated-decorators-and-three",
- "risk_tier": "R2 local user-facing media",
+ "risk_tier": "R2 local media",
+ "timestamp": "2026-09-05T07:00:31.276652+00:00",
"environment": "macOS; Chrome; HyperFrames 0.8.29; FFmpeg; Chrome DevTools MCP 1.8.0 isolated stdio",
- "timestamp": "2026-09-05T06:53:29.630101+00:00",
- "source_commit": "bca76813cc3c92d00f80c55562c5a4131a06123f",
- "animation_sha256": "54dda098e427ba14b77740ca704b1a0079d1bd1e733c1c955b57b72697e86a03",
- "baseline": "New project. Shared Chrome MCP profile busy; temporary isolated MCP browser successfully used without changing shared configuration.",
+ "baseline_commit": "5b8c104",
+ "animation_sha256": "2fe0ca2274ce82bb3a0024c60637ec9ae88af1b4ccf56ebdf38f224aec64131d",
"commands": [
"node scripts/build.mjs",
- "python3 scripts/audio.py",
"node scripts/production.cjs preview",
"node scripts/production.cjs check",
"node scripts/production.cjs render",
"node scripts/production.cjs verify",
"node scripts/production.cjs mcp",
- "ffprobe all three MP4s",
- "ffmpeg full decode, per-second framemd5, and volumedetect all three MP4s"
+ "ffmpeg full decode, per-second framemd5 and volumedetect"
],
"checks": [
{
"name": "01-runaway-roll animated timeline at 6 story beats",
"verdict": "PASS",
"sha256": [
- "ff1fe6e32a542aa2afd03413942f00517fcf9b5f658aa2ba3a95e3f9b84b8bd1",
- "43113f77cefce7118e980e0c1c4089c81ca05f2349782cf239abb844ad53ef69",
- "1f7d4f05efbaf04d06db2d45fdb3ac60deb40627d829ee2e288d5d2a65fe77ed",
- "986338c33a24afcb2e44386f4467c85680d8e3ad23e1d4ff426d04bf39865512",
- "732f938638877c170d2d388f8e79324aa28363627b52224e0cb411fa1327ee03",
- "01811e4036a2c006c4283e5e8b9556f7ead76792390701b95bc93982ebfefff0"
+ "aac4c5a322ca32b772864b05abd54805f00c28e40c83ebf730913edfc79bd0e3",
+ "eaf803c16785ab8b906e94551047dd3da55b0bf85b5647190ab3427aa23ac242",
+ "f09191be0d02c5618add56ec157d0e4c8266b58314b3b98556301254cb54c2b6",
+ "aca9a0d82b451805e3e9eeac7e8618ac7d3e3f6516663dc1c6c78f6b319e8d08",
+ "86a2e412be4537c012e6792c62edd4116aedacb113d3137c5f0e0f47814a4a88",
+ "9705f46cc62783addb34a44e4cc58aa654170aacd06250b8b02cb163513d85ac"
]
},
{
@@ -39,12 +36,12 @@
"name": "02-splash-of-personality animated timeline at 6 story beats",
"verdict": "PASS",
"sha256": [
- "0505b21ab4b92ee4fc7415fcdedf43666e9ca6ff0dcf81fa0528093b4ae307a9",
- "4d4aa7708355b6f0b6082a5c97aef160f51c99297ae2ebedf726502267b0a11a",
- "46ea209d31b4765292602f09c9dac83efecd4bf497faac44b879c56139077def",
- "25f30f60be9e82818e013cc44478b69309c7721935b93e599f015ebe5bd45164",
- "8d95f3eaf9f1e9cf1e39c5d0a65051b04e52e08a600db6dbf03f9a1eaf951f28",
- "56a58d15da4f68b24a2f6122be8c3142784f945d71a83cc2361d03286e7beae9"
+ "8dd8cfe148d9a608afedb7fffd76fb78feed5a57e630f433c5b6ae30c3fb4512",
+ "c775957583a29a484df3fb671f421c7b56cfc6edf84558afba36647434fba0df",
+ "27414fe2776557009e781319c35c34258ebd27ffd6844edd5a1ea1ee753e82ae",
+ "235cb916982eb2857a6ea4b94cfd1d462ebbcf2daeaf1675035d40bebd311639",
+ "c17ca08732cdf957acc974c02e31efc09b60cbef2baa0e790d1daae736d3b64e",
+ "fff404e48cb86841171378e4d24755226616d182ceffbe969fc97bd814e77309"
]
},
{
@@ -55,12 +52,12 @@
"name": "03-great-wall-off animated timeline at 6 story beats",
"verdict": "PASS",
"sha256": [
- "e2a239945d67a5a01fef314999a9e56873f03a84438c6cbefd6498381df5c765",
- "de142e76538aa75cde8cbafab598c780d22e57a4dd6f845e2985c3ba17773d03",
- "f41dd2820987b153c0eb91d27f9b5624ab99c86d2315a55b5443589bc7d577fb",
- "c22821c1b83207f39e9861d8e9910624a7618ef237aa3c85ca094fb078c0ee55",
- "5ff9d35d536918a1f3ee82eccc4c17aac948dc759f4717c51341d854ce089a34",
- "2754fc23c5ed029d81e826cba02ac709f24d252660c7808020f87dfbd70472cc"
+ "3c0e4395cce41eca538065e8a7e790a89bec385d5551404b361a5f623dcdfa9c",
+ "e9781ae5b9cac8d3d24e814ae6d23034563e3b9956890fe018ecf96847fb2d53",
+ "a6f773a06e8bb7cde6ca1b940bcb48f0a3001c1a628824220a103e892db6f681",
+ "ec1fa8af54d91f4cc1223dc54f369f468a0843f2fbc55de2e981745d5112789a",
+ "6a26cc1d2087e093e3af56fbeda26aa3c30f4a3dec37768dc865b11a736a8903",
+ "0f76f455b30e4097ee3a904b32d48da8428b8e3d8d8d87a7e1b4f0c276e809cd"
]
},
{
@@ -75,7 +72,7 @@
"name": "01-runaway-roll delivered file, full decode and real browser playback",
"verdict": "PASS",
"file": "/Users/macstudio3/Projects/wallpaper-paint-antics/renders/01-runaway-roll.mp4",
- "bytes": 15129136,
+ "bytes": 15136419,
"frames": "600",
"duration": "20.000000",
"audio": "aac",
@@ -84,13 +81,14 @@
"width": 1080,
"height": 1920,
"error": null
- }
+ },
+ "characterName": "Wallo"
},
{
"name": "02-splash-of-personality delivered file, full decode and real browser playback",
"verdict": "PASS",
"file": "/Users/macstudio3/Projects/wallpaper-paint-antics/renders/02-splash-of-personality.mp4",
- "bytes": 13083162,
+ "bytes": 13081448,
"frames": "600",
"duration": "20.000000",
"audio": "aac",
@@ -99,13 +97,14 @@
"width": 1080,
"height": 1920,
"error": null
- }
+ },
+ "characterName": "Wallo"
},
{
"name": "03-great-wall-off delivered file, full decode and real browser playback",
"verdict": "PASS",
"file": "/Users/macstudio3/Projects/wallpaper-paint-antics/renders/03-great-wall-off.mp4",
- "bytes": 15422604,
+ "bytes": 15427263,
"frames": "600",
"duration": "20.000000",
"audio": "aac",
@@ -114,82 +113,80 @@
"width": 1080,
"height": 1920,
"error": null
- }
+ },
+ "characterName": "Wallo"
},
{
"name": "No browser JavaScript errors",
"verdict": "PASS"
},
+ {
+ "name": "All active source, titles and asset paths use Wallo",
+ "verdict": "PASS"
+ },
{
"name": "HyperFrames lint/runtime/layout check",
"verdict": "PASS",
- "errors": 0,
- "warnings": 0
+ "evidence": "hyperframes-check.json"
},
{
- "name": "Contact sheet and rendered frames visually reviewed",
+ "name": "Rendered title and gallery visually reviewed",
"verdict": "PASS",
"evidence": [
- "contact-sheet.png",
- "02-splash-of-personality-mp4-19.png"
+ "02-splash-of-personality-mp4-19.png",
+ "mcp-gallery.png"
]
},
{
- "name": "Encoded video contains actual motion and audible soundtrack",
+ "name": "All three videos rerendered with motion and audible soundtrack",
"verdict": "PASS",
- "files": [
- {
- "file": "01-runaway-roll.mp4",
- "verdict": "PASS",
- "sampled_frames": 20,
- "distinct_frames": 20,
- "peak_db": -8.3,
- "sha256": "d63aa152f797a72f739fe12a69577dcff62676f3425c4fb96b0e45aeeb69c5d3"
- },
- {
- "file": "02-splash-of-personality.mp4",
- "verdict": "PASS",
- "sampled_frames": 20,
- "distinct_frames": 20,
- "peak_db": -4.7,
- "sha256": "eea8a3507c586b54a88639027c056cd3f56331fbc5470502cf317ce9b138e318"
- },
- {
- "file": "03-great-wall-off.mp4",
- "verdict": "PASS",
- "sampled_frames": 20,
- "distinct_frames": 20,
- "peak_db": -5.8,
- "sha256": "4a95efb33d38204f0550e4c8f866df75525fdd45ead51ed789ca001aea46ce9a"
- }
- ]
+ "evidence": {
+ "videos": [
+ {
+ "file": "01-runaway-roll.mp4",
+ "verdict": "PASS",
+ "sampled_frames": 20,
+ "distinct_frames": 20,
+ "peak_db": -8.3,
+ "sha256": "0cf70d41d4370767b33a88c66d0635bb4582a3aaeb541c3dd9a4d22fa97f92eb",
+ "rerendered": true
+ },
+ {
+ "file": "02-splash-of-personality.mp4",
+ "verdict": "PASS",
+ "sampled_frames": 20,
+ "distinct_frames": 20,
+ "peak_db": -4.7,
+ "sha256": "c8041cb3d177327359a1586f20e6312bc2075a7d54879a79298f6e3c2cca52a7",
+ "rerendered": true
+ },
+ {
+ "file": "03-great-wall-off.mp4",
+ "verdict": "PASS",
+ "sampled_frames": 20,
+ "distinct_frames": 20,
+ "peak_db": -5.8,
+ "sha256": "57b8cbb35ae189c9bfc6e3e82269d24973c908a5b3c7532d8d57462c8491a3af",
+ "rerendered": true
+ }
+ ],
+ "soundtrack_unchanged": true
+ }
},
{
- "name": "Chrome MCP gallery: 3 videos plus 2 characters, video clocks advance, both character PNGs exported",
+ "name": "Chrome MCP gallery playback and both character exports",
"verdict": "PASS",
"evidence": "mcp-proof.json"
- },
- {
- "name": "Canvas text contrast",
- "verdict": "PASS",
- "detail": "Calculated title 9.91:1, speech 11.08:1, footer 6.64:1; large teal label 4.05:1. HyperFrames DOM contrast does not audit canvas text. Gallery small teal text darkened to #206d6b."
}
],
- "negative_and_retry_checks": [
- "Backward seek produces byte-identical preview frame in all episodes.",
- "Shared MCP profile collision resolved with documented --isolated mode; no shared browser terminated.",
- "Preview-harness serialization of a GSAP timeline fixed by returning no value; successful rerun retained.",
- "Playback test uses readiness predicate rather than fixed initial delay; all 3 pass.",
- "MCP tool output path normalizes extension to .json; caller corrected and both exports verified."
- ],
"artifacts": [
"watch.html",
- "assets/wally.png",
+ "assets/wallo.png",
"assets/pippa.png",
"renders/01-runaway-roll.mp4",
"renders/02-splash-of-personality.mp4",
"renders/03-great-wall-off.mp4"
],
- "cleanup": "Temporary render/MCP/verification browsers closed. No published media, remote push, production catalog writes, or new paid provider. Only final local media, sources and evidence retained.",
+ "cleanup": "Temporary render and verification browsers closed. Final local media, sources and evidence retained.",
"verdict": "PASS"
}
diff --git a/verification/encoded-media-evidence.json b/verification/encoded-media-evidence.json
index 76fc2ef..5453cf1 100644
--- a/verification/encoded-media-evidence.json
+++ b/verification/encoded-media-evidence.json
@@ -1,26 +1,32 @@
-[
- {
- "file": "01-runaway-roll.mp4",
- "verdict": "PASS",
- "sampled_frames": 20,
- "distinct_frames": 20,
- "peak_db": -8.3,
- "sha256": "d63aa152f797a72f739fe12a69577dcff62676f3425c4fb96b0e45aeeb69c5d3"
- },
- {
- "file": "02-splash-of-personality.mp4",
- "verdict": "PASS",
- "sampled_frames": 20,
- "distinct_frames": 20,
- "peak_db": -4.7,
- "sha256": "eea8a3507c586b54a88639027c056cd3f56331fbc5470502cf317ce9b138e318"
- },
- {
- "file": "03-great-wall-off.mp4",
- "verdict": "PASS",
- "sampled_frames": 20,
- "distinct_frames": 20,
- "peak_db": -5.8,
- "sha256": "4a95efb33d38204f0550e4c8f866df75525fdd45ead51ed789ca001aea46ce9a"
- }
-]
\ No newline at end of file
+{
+ "videos": [
+ {
+ "file": "01-runaway-roll.mp4",
+ "verdict": "PASS",
+ "sampled_frames": 20,
+ "distinct_frames": 20,
+ "peak_db": -8.3,
+ "sha256": "0cf70d41d4370767b33a88c66d0635bb4582a3aaeb541c3dd9a4d22fa97f92eb",
+ "rerendered": true
+ },
+ {
+ "file": "02-splash-of-personality.mp4",
+ "verdict": "PASS",
+ "sampled_frames": 20,
+ "distinct_frames": 20,
+ "peak_db": -4.7,
+ "sha256": "c8041cb3d177327359a1586f20e6312bc2075a7d54879a79298f6e3c2cca52a7",
+ "rerendered": true
+ },
+ {
+ "file": "03-great-wall-off.mp4",
+ "verdict": "PASS",
+ "sampled_frames": 20,
+ "distinct_frames": 20,
+ "peak_db": -5.8,
+ "sha256": "57b8cbb35ae189c9bfc6e3e82269d24973c908a5b3c7532d8d57462c8491a3af",
+ "rerendered": true
+ }
+ ],
+ "soundtrack_unchanged": true
+}
diff --git a/verification/mcp-gallery.png b/verification/mcp-gallery.png
index c825fd4..6731502 100644
Binary files a/verification/mcp-gallery.png and b/verification/mcp-gallery.png differ
diff --git a/verification/mcp-proof.json b/verification/mcp-proof.json
index 792cb94..dd2a5b0 100644
--- a/verification/mcp-proof.json
+++ b/verification/mcp-proof.json
@@ -3,7 +3,7 @@
"version": "1.8.0",
"mode": "isolated headless",
"ticket": "TK-11286",
- "at": "2026-09-05T06:52:45.790Z",
+ "at": "2026-09-05T06:59:36.394Z",
"calls": [
{
"name": "new_page",
@@ -14,7 +14,7 @@
"content": [
{
"type": "text",
- "text": "## Pages\n1: about:blank\n2: Wally & Pippa — Three little decorating disasters (file:///Users/macstudio3/Projects/wallpaper-paint-antics/watch.html) [selected]"
+ "text": "## Pages\n1: about:blank\n2: Wallo & Pippa — Three little decorating disasters (file:///Users/macstudio3/Projects/wallpaper-paint-antics/watch.html) [selected]"
}
]
}
@@ -29,7 +29,7 @@
"content": [
{
"type": "text",
- "text": "Script ran on page and returned:\n```json\n{\"title\":\"Wally & Pippa — Three little decorating disasters\",\"videos\":3,\"characters\":2}\n```"
+ "text": "Script ran on page and returned:\n```json\n{\"title\":\"Wallo & Pippa — Three little decorating disasters\",\"videos\":3,\"characters\":2}\n```"
}
]
}
@@ -44,7 +44,7 @@
"content": [
{
"type": "text",
- "text": "Script ran on page and returned:\n```json\n[{\"slug\":\"01-runaway-roll\",\"duration\":20,\"currentTime\":0.425773,\"width\":1080,\"height\":1920,\"error\":null},{\"slug\":\"02-splash-of-personality\",\"duration\":20,\"currentTime\":0.449143,\"width\":1080,\"height\":1920,\"error\":null},{\"slug\":\"03-great-wall-off\",\"duration\":20,\"currentTime\":0.449481,\"width\":1080,\"height\":1920,\"error\":null}]\n```"
+ "text": "Script ran on page and returned:\n```json\n[{\"slug\":\"01-runaway-roll\",\"duration\":20,\"currentTime\":0.420167,\"width\":1080,\"height\":1920,\"error\":null},{\"slug\":\"02-splash-of-personality\",\"duration\":20,\"currentTime\":0.485883,\"width\":1080,\"height\":1920,\"error\":null},{\"slug\":\"03-great-wall-off\",\"duration\":20,\"currentTime\":0.450158,\"width\":1080,\"height\":1920,\"error\":null}]\n```"
}
]
}
@@ -76,7 +76,7 @@
"content": [
{
"type": "text",
- "text": "Successfully navigated to file:///Users/macstudio3/Projects/wallpaper-paint-antics/index.html.\n## Pages\n1: about:blank\n2: Wally & Pippa — 01-runaway-roll (file:///Users/macstudio3/Projects/wallpaper-paint-antics/index.html) [selected]"
+ "text": "Successfully navigated to file:///Users/macstudio3/Projects/wallpaper-paint-antics/index.html.\n## Pages\n1: about:blank\n2: Wallo & Pippa — 01-runaway-roll (file:///Users/macstudio3/Projects/wallpaper-paint-antics/index.html) [selected]"
}
]
}
@@ -85,11 +85,11 @@
"name": "evaluate_script",
"args": {
"pageId": 2,
- "function": "() => ({png:window.exportCharacter(\"wally\")})",
- "filePath": "/Users/macstudio3/Projects/wallpaper-paint-antics/verification/mcp-wally-export.json"
+ "function": "() => ({png:window.exportCharacter(\"wallo\")})",
+ "filePath": "/Users/macstudio3/Projects/wallpaper-paint-antics/verification/mcp-wallo-export.json"
},
"result": {
- "exported": "assets/wally.png",
+ "exported": "assets/wallo.png",
"bytes": 119832
}
},
diff --git a/verification/mcp-stderr.txt b/verification/mcp-stderr.txt
index 590d294..4bb8d2e 100644
--- a/verification/mcp-stderr.txt
+++ b/verification/mcp-stderr.txt
@@ -1,4 +1,4 @@
-(node:83412) ExperimentalWarning: localStorage is not available because --localstorage-file was not provided.
+(node:67451) ExperimentalWarning: localStorage is not available because --localstorage-file was not provided.
(Use `node --trace-warnings ...` to show where the warning was created)
chrome-devtools-mcp exposes content of the browser instance to the MCP clients allowing them to inspect,
debug, and modify any data in the browser or DevTools.
diff --git a/verification/mcp-wally-export.json b/verification/mcp-wallo-export.json
similarity index 100%
rename from verification/mcp-wally-export.json
rename to verification/mcp-wallo-export.json
diff --git a/verification/preview-evidence.json b/verification/preview-evidence.json
index e54ca98..825fbdf 100644
--- a/verification/preview-evidence.json
+++ b/verification/preview-evidence.json
@@ -1,17 +1,17 @@
{
"phase": "preview",
- "timestamp": "2026-09-05T06:45:54.090Z",
+ "timestamp": "2026-09-05T06:56:18.214Z",
"checks": [
{
"name": "01-runaway-roll animated timeline at 6 story beats",
"verdict": "PASS",
"sha256": [
- "ff1fe6e32a542aa2afd03413942f00517fcf9b5f658aa2ba3a95e3f9b84b8bd1",
- "43113f77cefce7118e980e0c1c4089c81ca05f2349782cf239abb844ad53ef69",
- "1f7d4f05efbaf04d06db2d45fdb3ac60deb40627d829ee2e288d5d2a65fe77ed",
- "986338c33a24afcb2e44386f4467c85680d8e3ad23e1d4ff426d04bf39865512",
- "732f938638877c170d2d388f8e79324aa28363627b52224e0cb411fa1327ee03",
- "01811e4036a2c006c4283e5e8b9556f7ead76792390701b95bc93982ebfefff0"
+ "aac4c5a322ca32b772864b05abd54805f00c28e40c83ebf730913edfc79bd0e3",
+ "eaf803c16785ab8b906e94551047dd3da55b0bf85b5647190ab3427aa23ac242",
+ "f09191be0d02c5618add56ec157d0e4c8266b58314b3b98556301254cb54c2b6",
+ "aca9a0d82b451805e3e9eeac7e8618ac7d3e3f6516663dc1c6c78f6b319e8d08",
+ "86a2e412be4537c012e6792c62edd4116aedacb113d3137c5f0e0f47814a4a88",
+ "9705f46cc62783addb34a44e4cc58aa654170aacd06250b8b02cb163513d85ac"
]
},
{
@@ -22,12 +22,12 @@
"name": "02-splash-of-personality animated timeline at 6 story beats",
"verdict": "PASS",
"sha256": [
- "0505b21ab4b92ee4fc7415fcdedf43666e9ca6ff0dcf81fa0528093b4ae307a9",
- "4d4aa7708355b6f0b6082a5c97aef160f51c99297ae2ebedf726502267b0a11a",
- "46ea209d31b4765292602f09c9dac83efecd4bf497faac44b879c56139077def",
- "25f30f60be9e82818e013cc44478b69309c7721935b93e599f015ebe5bd45164",
- "8d95f3eaf9f1e9cf1e39c5d0a65051b04e52e08a600db6dbf03f9a1eaf951f28",
- "56a58d15da4f68b24a2f6122be8c3142784f945d71a83cc2361d03286e7beae9"
+ "8dd8cfe148d9a608afedb7fffd76fb78feed5a57e630f433c5b6ae30c3fb4512",
+ "c775957583a29a484df3fb671f421c7b56cfc6edf84558afba36647434fba0df",
+ "27414fe2776557009e781319c35c34258ebd27ffd6844edd5a1ea1ee753e82ae",
+ "235cb916982eb2857a6ea4b94cfd1d462ebbcf2daeaf1675035d40bebd311639",
+ "c17ca08732cdf957acc974c02e31efc09b60cbef2baa0e790d1daae736d3b64e",
+ "fff404e48cb86841171378e4d24755226616d182ceffbe969fc97bd814e77309"
]
},
{
@@ -38,12 +38,12 @@
"name": "03-great-wall-off animated timeline at 6 story beats",
"verdict": "PASS",
"sha256": [
- "e2a239945d67a5a01fef314999a9e56873f03a84438c6cbefd6498381df5c765",
- "de142e76538aa75cde8cbafab598c780d22e57a4dd6f845e2985c3ba17773d03",
- "f41dd2820987b153c0eb91d27f9b5624ab99c86d2315a55b5443589bc7d577fb",
- "c22821c1b83207f39e9861d8e9910624a7618ef237aa3c85ca094fb078c0ee55",
- "5ff9d35d536918a1f3ee82eccc4c17aac948dc759f4717c51341d854ce089a34",
- "2754fc23c5ed029d81e826cba02ac709f24d252660c7808020f87dfbd70472cc"
+ "3c0e4395cce41eca538065e8a7e790a89bec385d5551404b361a5f623dcdfa9c",
+ "e9781ae5b9cac8d3d24e814ae6d23034563e3b9956890fe018ecf96847fb2d53",
+ "a6f773a06e8bb7cde6ca1b940bcb48f0a3001c1a628824220a103e892db6f681",
+ "ec1fa8af54d91f4cc1223dc54f369f468a0843f2fbc55de2e981745d5112789a",
+ "6a26cc1d2087e093e3af56fbeda26aa3c30f4a3dec37768dc865b11a736a8903",
+ "0f76f455b30e4097ee3a904b32d48da8428b8e3d8d8d87a7e1b4f0c276e809cd"
]
},
{
diff --git a/verification/rename-baseline.json b/verification/rename-baseline.json
new file mode 100644
index 0000000..377828d
--- /dev/null
+++ b/verification/rename-baseline.json
@@ -0,0 +1,13 @@
+{
+ "previous_commit": "5b8c104",
+ "videos": {
+ "01-runaway-roll.mp4": "d63aa152f797a72f739fe12a69577dcff62676f3425c4fb96b0e45aeeb69c5d3",
+ "02-splash-of-personality.mp4": "eea8a3507c586b54a88639027c056cd3f56331fbc5470502cf317ce9b138e318",
+ "03-great-wall-off.mp4": "4a95efb33d38204f0550e4c8f866df75525fdd45ead51ed789ca001aea46ce9a"
+ },
+ "audio": {
+ "short-2.wav": "e62977293b18f7d573018821540e6e0817f2fa85125c941d28d7a993b72856a9",
+ "short-3.wav": "04ea0cb7ec1be0bc6fb1f4bb0fd02ea424b0bc7f018e478fd5d76f5b028fa68b",
+ "short-1.wav": "6a9c22db0004eceb85125dae6abf1a7e383ed40961b4617e7035fcab00e7cb3d"
+ }
+}
diff --git a/verification/verify-evidence.json b/verification/verify-evidence.json
index 4971fe5..9e7fe7d 100644
--- a/verification/verify-evidence.json
+++ b/verification/verify-evidence.json
@@ -1,12 +1,12 @@
{
"phase": "verify",
- "timestamp": "2026-09-05T06:49:14.181Z",
+ "timestamp": "2026-09-05T06:59:41.299Z",
"checks": [
{
"name": "01-runaway-roll delivered file, full decode and real browser playback",
"verdict": "PASS",
"file": "/Users/macstudio3/Projects/wallpaper-paint-antics/renders/01-runaway-roll.mp4",
- "bytes": 15129136,
+ "bytes": 15136419,
"frames": "600",
"duration": "20.000000",
"audio": "aac",
@@ -15,13 +15,14 @@
"width": 1080,
"height": 1920,
"error": null
- }
+ },
+ "characterName": "Wallo"
},
{
"name": "02-splash-of-personality delivered file, full decode and real browser playback",
"verdict": "PASS",
"file": "/Users/macstudio3/Projects/wallpaper-paint-antics/renders/02-splash-of-personality.mp4",
- "bytes": 13083162,
+ "bytes": 13081448,
"frames": "600",
"duration": "20.000000",
"audio": "aac",
@@ -30,13 +31,14 @@
"width": 1080,
"height": 1920,
"error": null
- }
+ },
+ "characterName": "Wallo"
},
{
"name": "03-great-wall-off delivered file, full decode and real browser playback",
"verdict": "PASS",
"file": "/Users/macstudio3/Projects/wallpaper-paint-antics/renders/03-great-wall-off.mp4",
- "bytes": 15422604,
+ "bytes": 15427263,
"frames": "600",
"duration": "20.000000",
"audio": "aac",
@@ -45,7 +47,8 @@
"width": 1080,
"height": 1920,
"error": null
- }
+ },
+ "characterName": "Wallo"
},
{
"name": "No browser JavaScript errors",
diff --git a/watch.html b/watch.html
index a2f30db..f97333e 100644
--- a/watch.html
+++ b/watch.html
@@ -1 +1 @@
-<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Wally & Pippa — Three little decorating disasters</title><style>@font-face{font-family:Archivo;src:url('assets/archivo.ttf')}*{box-sizing:border-box}body{margin:0;background:#f4eadb;color:#243b42;font:17px/1.5 system-ui,sans-serif}main{max-width:1240px;padding:55px 28px 80px;margin:auto}header{border-bottom:3px solid #243b42;margin-bottom:34px}h1{font:clamp(38px,6vw,82px)/1 Archivo,sans-serif;letter-spacing:-.04em;margin:0 0 22px}.eyebrow{color:#206d6b;font-weight:800;letter-spacing:.13em;text-transform:uppercase;font-size:13px}.intro{max-width:750px;font-size:21px}.cast{display:flex;gap:26px;align-items:center;margin:24px 0 36px}.cast img{height:230px;object-fit:contain}.cast p{max-width:480px}.films{display:flex;gap:24px;align-items:flex-start}article{flex:1;min-width:0}video{display:block;width:100%;aspect-ratio:9/16;background:#243b42;border-radius:16px}h2{font:24px/1.2 Archivo,sans-serif;margin:18px 0 7px}a{color:#206d6b;font-weight:700}.meta{font-size:14px}footer{margin-top:45px;border-top:2px solid #cbb99c;padding-top:22px;font-size:14px}@media(max-width:750px){.films{flex-direction:column}article{max-width:470px;width:100%;margin:0 auto 30px}.cast{flex-wrap:wrap}.cast img{height:180px}}</style></head><body><main><header><p class="eyebrow">Meet your new decorating double act</p><h1>Wally & Pippa.</h1><p class="intro">One loves a perfect pattern. The other can’t resist a splash of color. Somehow, the room always comes together.</p></header><section class="cast"><img src="assets/wally.png" alt="Wally, the wallpaper installer"><img src="assets/pippa.png" alt="Pippa, the painter"><p><b>Wally</b> — the meticulous paperhanger with the mustard cap.<br><b>Pippa</b> — the fearless painter with an oversized sense of fun.<br><a href="assets/wally.png" download>Wally character PNG</a> · <a href="assets/pippa.png" download>Pippa character PNG</a></p></section><div class="films"><article><video data-slug="01-runaway-roll" controls playsinline preload="metadata" poster="verification/01-runaway-roll-19.png" src="renders/01-runaway-roll.mp4"></video><h2>The runaway roll</h2><p>The wallpaper has plans of its own.</p><p class="meta">20 seconds · 1080 × 1920 · sound on</p><a href="renders/01-runaway-roll.mp4" download>Download MP4</a></article><article><video data-slug="02-splash-of-personality" controls playsinline preload="metadata" poster="verification/02-splash-of-personality-19.png" src="renders/02-splash-of-personality.mp4"></video><h2>A splash of personality</h2><p>A roller flourish becomes accidental art.</p><p class="meta">20 seconds · 1080 × 1920 · sound on</p><a href="renders/02-splash-of-personality.mp4" download>Download MP4</a></article><article><video data-slug="03-great-wall-off" controls playsinline preload="metadata" poster="verification/03-great-wall-off-19.png" src="renders/03-great-wall-off.mp4"></video><h2>The great wall-off</h2><p>A race ends with a much better partnership.</p><p class="meta">20 seconds · 1080 × 1920 · sound on</p><a href="renders/03-great-wall-off.mp4" download>Download MP4</a></article></div><footer>Original character animation, music and sound effects. Created September 4, 2026. Local review copy.</footer></main></body></html>
+<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Wallo & Pippa — Three little decorating disasters</title><style>@font-face{font-family:Archivo;src:url('assets/archivo.ttf')}*{box-sizing:border-box}body{margin:0;background:#f4eadb;color:#243b42;font:17px/1.5 system-ui,sans-serif}main{max-width:1240px;padding:55px 28px 80px;margin:auto}header{border-bottom:3px solid #243b42;margin-bottom:34px}h1{font:clamp(38px,6vw,82px)/1 Archivo,sans-serif;letter-spacing:-.04em;margin:0 0 22px}.eyebrow{color:#206d6b;font-weight:800;letter-spacing:.13em;text-transform:uppercase;font-size:13px}.intro{max-width:750px;font-size:21px}.cast{display:flex;gap:26px;align-items:center;margin:24px 0 36px}.cast img{height:230px;object-fit:contain}.cast p{max-width:480px}.films{display:flex;gap:24px;align-items:flex-start}article{flex:1;min-width:0}video{display:block;width:100%;aspect-ratio:9/16;background:#243b42;border-radius:16px}h2{font:24px/1.2 Archivo,sans-serif;margin:18px 0 7px}a{color:#206d6b;font-weight:700}.meta{font-size:14px}footer{margin-top:45px;border-top:2px solid #cbb99c;padding-top:22px;font-size:14px}@media(max-width:750px){.films{flex-direction:column}article{max-width:470px;width:100%;margin:0 auto 30px}.cast{flex-wrap:wrap}.cast img{height:180px}}</style></head><body><main><header><p class="eyebrow">Meet your new decorating double act</p><h1>Wallo & Pippa.</h1><p class="intro">One loves a perfect pattern. The other can’t resist a splash of color. Somehow, the room always comes together.</p></header><section class="cast"><img src="assets/wallo.png" alt="Wallo, the wallpaper installer"><img src="assets/pippa.png" alt="Pippa, the painter"><p><b>Wallo</b> — the meticulous paperhanger with the mustard cap.<br><b>Pippa</b> — the fearless painter with an oversized sense of fun.<br><a href="assets/wallo.png" download>Wallo character PNG</a> · <a href="assets/pippa.png" download>Pippa character PNG</a></p></section><div class="films"><article><video data-slug="01-runaway-roll" controls playsinline preload="metadata" poster="verification/01-runaway-roll-19.png" src="renders/01-runaway-roll.mp4"></video><h2>The runaway roll</h2><p>The wallpaper has plans of its own.</p><p class="meta">20 seconds · 1080 × 1920 · sound on</p><a href="renders/01-runaway-roll.mp4" download>Download MP4</a></article><article><video data-slug="02-splash-of-personality" controls playsinline preload="metadata" poster="verification/02-splash-of-personality-19.png" src="renders/02-splash-of-personality.mp4"></video><h2>A splash of personality</h2><p>A roller flourish becomes accidental art.</p><p class="meta">20 seconds · 1080 × 1920 · sound on</p><a href="renders/02-splash-of-personality.mp4" download>Download MP4</a></article><article><video data-slug="03-great-wall-off" controls playsinline preload="metadata" poster="verification/03-great-wall-off-19.png" src="renders/03-great-wall-off.mp4"></video><h2>The great wall-off</h2><p>A race ends with a much better partnership.</p><p class="meta">20 seconds · 1080 × 1920 · sound on</p><a href="renders/03-great-wall-off.mp4" download>Download MP4</a></article></div><footer>Original character animation, music and sound effects. Created September 4, 2026. Local review copy.</footer></main></body></html>
← 5b8c104 Verify three finished shorts and export characters through C
·
back to Wallpaper Paint Antics
·
auto-data-snapshot: 2026-09-05T00:27:41 (16 data files) — se 5c47244 →