← back to Scarlet Riverboat Masquerade
Keep animals/cubs grounded (lower hop/bounce); add pterodactyl fly-over (button + key p) soaring across the canyon
1043c035abfcc61dad453ae6d69fba45f038f5cc · 2026-09-01 18:35:33 -0700 · Steve Abrams
Files touched
Diff
commit 1043c035abfcc61dad453ae6d69fba45f038f5cc
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Sep 1 18:35:33 2026 -0700
Keep animals/cubs grounded (lower hop/bounce); add pterodactyl fly-over (button + key p) soaring across the canyon
---
index.html | 44 ++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 42 insertions(+), 2 deletions(-)
diff --git a/index.html b/index.html
index ee50823..9773e2f 100644
--- a/index.html
+++ b/index.html
@@ -256,6 +256,7 @@
<button class="btn" id="reduceBtn" aria-pressed="false">◐ Reduced Motion</button>
<button class="btn" id="trailBtn" aria-pressed="true">✧ Motion Trails</button>
<button class="btn" id="reactBtn" aria-pressed="false">♫ React to Music</button>
+ <button class="btn" id="pteroBtn">🦖 Fly Over</button>
</div>
</div>
<div class="group">
@@ -816,7 +817,7 @@ function rabbit(x,y,s,t,accent){
const cyc=(t*1.6)%(Math.PI*2);
const air=Math.max(0,Math.sin(cyc));
const stretch=1+air*0.4, squash=1-Math.max(0,-Math.sin(cyc))*0.35;
- const hopY=-air*26;
+ const hopY=-air*9; // low, grounded hop — stays on the shore
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);
@@ -871,7 +872,7 @@ function bearAndFireflies(x,y,s,t,accent){
// two bear cubs dancing beside the conductor — bob + rock, bouncing harder on the beat when reactive
function bearCub(x,y,s,t,ph){
const beat=(S.pulse||0), amp=(S.amp||0);
- const bounce=Math.abs(Math.sin(t*2.4+ph))*(4+beat*11+amp*6);
+ 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)';
@@ -956,6 +957,40 @@ function drawFireworks(dt){
}
let _seenBeat=0;
+// ---------- Pterodactyl fly-over (button / key 'p') ----------
+let ptero=null;
+function launchPtero(){
+ ptero={ p:0, y:S.H*(0.12+Math.random()*0.14), dir:(Math.random()<0.5?1:-1), scale:1.3+Math.random()*0.7 };
+ announce('A pterodactyl glides across the canyon.');
+}
+function drawPtero(dt){
+ if(!ptero) return;
+ ptero.p += dt*0.16; // crosses in ~6s
+ if(ptero.p>=1){ ptero=null; return; }
+ const W=S.W, span=W+280;
+ const x = ptero.dir>0 ? -140+ptero.p*span : W+140-ptero.p*span;
+ const y = ptero.y + Math.sin(ptero.p*Math.PI*2.4)*22; // soaring undulation
+ const flap = S.reduced?0.5:(Math.sin(S.t*7)*0.5+0.5); // wingbeat
+ ctx.save(); ctx.translate(x,y); ctx.scale(ptero.dir*ptero.scale, ptero.scale);
+ ctx.fillStyle='rgba(14,4,8,0.9)';
+ // wings (flapping) + body
+ ctx.beginPath();
+ ctx.moveTo(0,0);
+ ctx.quadraticCurveTo(-16,-8-flap*22,-44,-3);
+ ctx.quadraticCurveTo(-18,6,-4,4);
+ ctx.lineTo(4,4);
+ ctx.quadraticCurveTo(18,6,44,-3);
+ ctx.quadraticCurveTo(16,-8-flap*22,0,0);
+ ctx.closePath(); ctx.fill();
+ // long beak forward
+ ctx.beginPath(); ctx.moveTo(3,0); ctx.lineTo(22,-3); ctx.lineTo(4,3); ctx.closePath(); ctx.fill();
+ // swept-back head crest
+ ctx.beginPath(); ctx.moveTo(2,-1); ctx.lineTo(-7,-10); ctx.lineTo(5,-2); ctx.closePath(); ctx.fill();
+ // trailing tail
+ ctx.strokeStyle='rgba(14,4,8,0.9)'; ctx.lineWidth=1.6; ctx.beginPath(); ctx.moveTo(-2,2); ctx.lineTo(-16,6); ctx.stroke();
+ ctx.restore();
+}
+
// ---------- Main loop ----------
let last=performance.now();
function frame(now){
@@ -1006,6 +1041,7 @@ function frame(now){
drawRiver();
drawAnimals();
drawBoat();
+ drawPtero(dt);
drawFireworks(dt);
requestAnimationFrame(frame);
@@ -1122,6 +1158,7 @@ window.addEventListener('keydown',e=>{
case 'm': reduceBtn.click(); break;
case 't': trailBtn.click(); break;
case 'a': { const rb=document.getElementById('reactBtn'); if(rb) rb.click(); } break;
+ case 'p': launchPtero(); break;
case '1': document.querySelector('[data-cam="wide"]').click(); break;
case '2': document.querySelector('[data-cam="deck"]').click(); break;
case '3': document.querySelector('[data-cam="over"]').click(); break;
@@ -1131,6 +1168,9 @@ window.addEventListener('keydown',e=>{
}
});
+// pterodactyl fly-over button
+document.getElementById('pteroBtn').addEventListener('click', launchPtero);
+
// click / tap anywhere on the scene (not on a control) to launch a firework
document.getElementById('stage').addEventListener('pointerdown', e=>{
if(e.target.closest('button,input,select,a,.dock,.cams,.chapters,.musicroom,.museum,.label-toggle')) return;
← b8b147f Add Photoshop-composited canyon-backdrop.png asset + two dan
·
back to Scarlet Riverboat Masquerade
·
Cutout/South-Park art pass: flat-color fills + bold dark out 1842974 →