[object Object]

← back to Dead Agentabrams

Sync ROOM 01: cutout animals + paper grain

12d58b3f22d528afd202ff5654187e07fe13ebd5 · 2026-09-01 18:40:51 -0700 · Steve Abrams

Files touched

Diff

commit 12d58b3f22d528afd202ff5654187e07fe13ebd5
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Sep 1 18:40:51 2026 -0700

    Sync ROOM 01: cutout animals + paper grain
---
 room/index.html | 54 ++++++++++++++++++++++++++++++++----------------------
 1 file changed, 32 insertions(+), 22 deletions(-)

diff --git a/room/index.html b/room/index.html
index 9773e2f..19a1b72 100644
--- a/room/index.html
+++ b/room/index.html
@@ -23,6 +23,9 @@
   html,body{margin:0;height:100%;background:#0a0406;color:var(--ink);font-family:var(--sans);overflow:hidden}
   #stage{position:fixed;inset:0;display:block}
   canvas{position:absolute;inset:0;width:100%;height:100%}
+  /* construction-paper grain — the cutout/South-Park texture over the whole scene */
+  .grain{position:fixed;inset:0;pointer-events:none;z-index:5;opacity:.10;mix-blend-mode:overlay;
+    background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 220 220' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}
 
   /* ---- Skip link ---- */
   .skip{
@@ -202,6 +205,7 @@
 
   <canvas id="sky" aria-hidden="true"></canvas>
   <canvas id="scene" aria-hidden="true"></canvas>
+  <div class="grain" aria-hidden="true"></div>
 
   <div class="titleplate">
     <p class="kicker">A Riverboat Listening Room</p>
@@ -388,6 +392,11 @@ function pal(key,i){ // blended palette between integer chapters
 // Choreography snaps to the nearest chapter (palette blends, steps change crisply)
 function CH(){ return CHAPTERS[clamp(Math.round(S.chapterMix),0,2)].choreo; }
 
+// cutout ("South Park") styling: flat fill + a bold dark outline, round joins
+const OUTLINE='rgba(8,3,5,0.92)';
+function cut(fill,w){ ctx.fillStyle=fill; ctx.strokeStyle=OUTLINE; ctx.lineWidth=w||2.4; ctx.lineJoin='round'; ctx.lineCap='round'; }
+function fillOutline(){ ctx.fill(); ctx.stroke(); }   // paint the current path as a cutout shape
+
 // ---------- Resize ----------
 function resize(){
   S.DPR = Math.min(2, window.devicePixelRatio||1);
@@ -773,10 +782,10 @@ function fox(x,y,s,t,accent){
   const gait=Math.sin(t*3.2);
   const bob=Math.abs(Math.sin(t*3.2))*-4;
   ctx.save(); ctx.translate(x + Math.sin(t*0.4)*30, y+bob); ctx.scale(s,s);
-  ctx.fillStyle='rgba(30,8,12,0.95)';
-  ctx.beginPath(); ctx.ellipse(0,-10,15,7,0,0,7); ctx.fill();
-  ctx.beginPath(); ctx.moveTo(12,-14); ctx.lineTo(24,-16); ctx.lineTo(13,-8); ctx.closePath(); ctx.fill();
-  ctx.beginPath(); ctx.moveTo(14,-18); ctx.lineTo(17,-24); ctx.lineTo(19,-17);ctx.closePath(); ctx.fill();
+  cut('rgba(150,58,42,0.98)');
+  ctx.beginPath(); ctx.ellipse(0,-10,15,7,0,0,7); fillOutline();
+  ctx.beginPath(); ctx.moveTo(12,-14); ctx.lineTo(24,-16); ctx.lineTo(13,-8); ctx.closePath(); fillOutline();
+  ctx.beginPath(); ctx.moveTo(14,-18); ctx.lineTo(17,-24); ctx.lineTo(19,-17);ctx.closePath(); fillOutline();
   ctx.strokeStyle=accent; ctx.lineWidth=5; ctx.lineCap='round'; ctx.globalAlpha=0.8;
   ctx.beginPath(); ctx.moveTo(-14,-10); ctx.quadraticCurveTo(-26,-14-gait*5,-30,-4-gait*3); ctx.stroke();
   ctx.globalAlpha=1;
@@ -801,9 +810,10 @@ function heron(x,y,s,t,accent){
   ctx.moveTo(-2,-18); ctx.lineTo(-4,2+ (step>0?0:step*8));
   ctx.moveTo(3,-18);  ctx.lineTo(5,2+ (step>0?step*8:0));
   ctx.stroke();
-  ctx.beginPath(); ctx.ellipse(0,-24,10,7,-0.2,0,7); ctx.fill();
+  cut('rgba(96,44,66,0.98)');
+  ctx.beginPath(); ctx.ellipse(0,-24,10,7,-0.2,0,7); fillOutline();
   ctx.save(); ctx.translate(0,-26); ctx.rotate(wing*0.6);
-  ctx.beginPath(); ctx.moveTo(0,0); ctx.quadraticCurveTo(-14,-4,-20,4); ctx.quadraticCurveTo(-10,2,0,3); ctx.closePath(); ctx.fill();
+  ctx.beginPath(); ctx.moveTo(0,0); ctx.quadraticCurveTo(-14,-4,-20,4); ctx.quadraticCurveTo(-10,2,0,3); ctx.closePath(); fillOutline();
   ctx.restore();
   ctx.lineWidth=2.4;
   ctx.beginPath(); ctx.moveTo(6,-28);
@@ -821,9 +831,9 @@ function rabbit(x,y,s,t,accent){
   ctx.save();
   ctx.translate(x + ((t*22)% (S.W*0.14)) - S.W*0.05, y+hopY);
   ctx.scale(s*(2-stretch)*0.9 + s*0.1, s*stretch*squash);
-  ctx.fillStyle='rgba(34,10,14,0.95)';
-  ctx.beginPath(); ctx.ellipse(0,-8,9,7,0,0,7); ctx.fill();
-  ctx.beginPath(); ctx.arc(8,-12,4.5,0,7); ctx.fill();
+  cut('rgba(120,66,60,0.98)',2);
+  ctx.beginPath(); ctx.ellipse(0,-8,9,7,0,0,7); fillOutline();
+  ctx.beginPath(); ctx.arc(8,-12,4.5,0,7); fillOutline();
   const ear = air*0.8;
   ctx.save(); ctx.translate(8,-15); ctx.rotate(ear);
   ctx.beginPath(); ctx.ellipse(0,-6,2,6,0.2,0,7); ctx.fill();
@@ -839,13 +849,13 @@ function rabbit(x,y,s,t,accent){
 function bearAndFireflies(x,y,s,t,accent){
   const wob=Math.sin(t*0.35)*3;
   ctx.save(); ctx.translate(x+wob,y); ctx.scale(s,s);
-  ctx.fillStyle='rgba(20,6,10,0.97)';
-  ctx.beginPath(); ctx.ellipse(0,-16,18,20,0,0,7); ctx.fill();
-  ctx.beginPath(); ctx.ellipse(-14,-2,10,8,0,0,7); ctx.fill();
-  ctx.beginPath(); ctx.ellipse(14,-2,10,8,0,0,7); ctx.fill();
-  ctx.beginPath(); ctx.arc(0,-36,11,0,7); ctx.fill();
-  ctx.beginPath(); ctx.arc(-9,-45,4,0,7); ctx.fill();
-  ctx.beginPath(); ctx.arc(9,-45,4,0,7); ctx.fill();
+  cut('rgba(74,34,34,0.98)',2.8);
+  ctx.beginPath(); ctx.ellipse(0,-16,18,20,0,0,7); fillOutline();
+  ctx.beginPath(); ctx.ellipse(-14,-2,10,8,0,0,7); fillOutline();
+  ctx.beginPath(); ctx.ellipse(14,-2,10,8,0,0,7); fillOutline();
+  ctx.beginPath(); ctx.arc(0,-36,11,0,7); fillOutline();
+  ctx.beginPath(); ctx.arc(-9,-45,4,0,7); fillOutline();
+  ctx.beginPath(); ctx.arc(9,-45,4,0,7); fillOutline();
   ctx.strokeStyle='rgba(20,6,10,0.97)'; ctx.lineWidth=6; ctx.lineCap='round';
   const ax=Math.sin(t*0.7)*16, ay=-Math.abs(Math.cos(t*0.7))*10;
   ctx.beginPath(); ctx.moveTo(6,-24); ctx.quadraticCurveTo(16,-34,18+ax,-40+ay); ctx.stroke();
@@ -875,12 +885,12 @@ function bearCub(x,y,s,t,ph){
   const bounce=Math.abs(Math.sin(t*2.4+ph))*(2+beat*4+amp*2.5);   // a grounded bop — feet stay near the shore
   const rock=Math.sin(t*2.4+ph)*0.2;
   ctx.save(); ctx.translate(x,y-bounce); ctx.rotate(rock); ctx.scale(s,s);
-  ctx.fillStyle='rgba(24,7,11,0.96)';
-  ctx.beginPath(); ctx.ellipse(0,-8,7,9,0,0,7); ctx.fill();        // body
-  ctx.beginPath(); ctx.arc(0,-20,6,0,7); ctx.fill();               // head
-  ctx.beginPath(); ctx.arc(-5,-25,2.5,0,7); ctx.fill();            // ears
-  ctx.beginPath(); ctx.arc(5,-25,2.5,0,7); ctx.fill();
-  ctx.strokeStyle='rgba(24,7,11,0.96)'; ctx.lineWidth=3; ctx.lineCap='round';
+  cut('rgba(88,42,40,0.98)',2);
+  ctx.beginPath(); ctx.ellipse(0,-8,7,9,0,0,7); fillOutline();     // body
+  ctx.beginPath(); ctx.arc(0,-20,6,0,7); fillOutline();            // head
+  ctx.beginPath(); ctx.arc(-5,-25,2.5,0,7); fillOutline();         // ears
+  ctx.beginPath(); ctx.arc(5,-25,2.5,0,7); fillOutline();
+  ctx.strokeStyle=OUTLINE; ctx.lineWidth=3; ctx.lineCap='round';
   const sw=Math.sin(t*4.8+ph)*3;                                   // arms wave in the dance
   ctx.beginPath();
   ctx.moveTo(-5,-11); ctx.lineTo(-10+sw,-17);

← 9a930f0 Sync ROOM 01: grounded animals + pterodactyl fly-over  ·  back to Dead Agentabrams  ·  Sync ROOM 01: full cutout dancers + boat f52b545 →