From 0648ae64f50dad497d9a74764a69a2d40d1a2afc Mon Sep 17 00:00:00 2001 From: "prompt.ac/@jeffrey" Date: Thu, 24 Sep 2026 17:04:27 -0700 Subject: [PATCH] Fleet: the laptops show only the word being sung Co-Authored-By: Claude Fable 5.1 --- .../macneopolitan/fleet/native-trio.mjs | 66 +++++++------------ 1 file changed, 22 insertions(+), 44 deletions(-) diff --git a/grants/culturehub-la-2026/macneopolitan/fleet/native-trio.mjs b/grants/culturehub-la-2026/macneopolitan/fleet/native-trio.mjs index d6d35195f4..751b23431e 100644 --- a/grants/culturehub-la-2026/macneopolitan/fleet/native-trio.mjs +++ b/grants/culturehub-la-2026/macneopolitan/fleet/native-trio.mjs @@ -110,7 +110,7 @@ const NOTE_RGB={c:[255,50,50],d:[255,160,0],e:[255,230,0],f:[50,200,50],g:[50,12 const NAMES=['c','c#','d','d#','e','f','f#','g','g#','a','a#','b']; function noteRgb(midi){const n=NAMES[((midi%12)+12)%12];return n.includes('#')?[235,235,235]:NOTE_RGB[n];} const KIND={kick:{lane:0,rgb:[255,90,60]},boom:{lane:0,rgb:[200,40,40]},snare:{lane:1,rgb:[245,245,245]},donk:{lane:1,rgb:[255,170,40]},hat:{lane:2,rgb:[170,170,170]},perc:{lane:1,rgb:[220,220,220]},riser:{lane:3,rgb:[120,200,255]},voice:{lane:3,rgb:[255,120,200]}}; -let noteCursor=0,routeCursor=0,lastPaintT=-1; +let noteCursor=0,wordCursor=0,routeCursor=0,lastPaintT=-1; // Per-frame budgets: the roll draws at most NOTES marks (this seat's own // always, the room's until OTHERS), LABELS note names, and merges a run of // ticks in one lane closer than MERGE seconds. No arrays are made per frame. @@ -154,56 +154,34 @@ function drawKaraoke(write,ink,line,t,x0,y0,size,rowH,w,litRGB,dimRGB){ } return rowsOut.length; } -export function paint({sound,wipe,ink,box,write,screen}){ +export function paint({sound,wipe,ink,write,screen}){ + // Active words only. The seat's colour edge to edge and the word being + // sung, huge, centred; the singer's name small above it. Nothing else. const w=screen.width,h=screen.height,t=origin===null?-1:sound.time-origin,active=phase==='playing'; const color=cfg?.color||[143,209,63]; const live=phase==='playing'||phase==='countdown'||phase==='prepared'; const bg=live?color:color.map(v=>Math.round(v*.35));wipe(...bg); - const lum=(0.2126*bg[0]+0.7152*bg[1]+0.0722*bg[2])/255,dark=lum>.5; - const inkRGB=dark?[8,8,12]:[250,250,250]; - const dimRGB=dark?[Math.round(bg[0]*.55),Math.round(bg[1]*.55),Math.round(bg[2]*.55)]:[Math.round(bg[0]*.5+110),Math.round(bg[1]*.5+110),Math.round(bg[2]*.5+110)]; - const tintRGB=dark?[Math.min(255,bg[0]+40),Math.min(255,bg[1]+40),Math.min(255,bg[2]+40)]:[Math.round(bg[0]*.7),Math.round(bg[1]*.7),Math.round(bg[2]*.7)]; + const lum=(0.2126*bg[0]+0.7152*bg[1]+0.0722*bg[2])/255; + const inkRGB=lum>.5?[8,8,12]:[250,250,250],dimRGB=lum>.5?[Math.round(bg[0]*.55),Math.round(bg[1]*.55),Math.round(bg[2]*.55)]:[Math.round(bg[0]*.5+110),Math.round(bg[1]*.5+110),Math.round(bg[2]*.5+110)]; if(!cfg)return; if(error){ink(...inkRGB);write(error,{x:8,y:h-24,font:FONT,size:1});return;} - if(phase==='countdown'){const left=Math.max(0,origin-sound.time);ink(...inkRGB);centered(write,String(Math.ceil(left)),Math.round(h/2-40),8,w);ink(...dimRGB);centered(write,(cfg.title||'').toLowerCase(),Math.round(h/2+50),2,w);return;} + if(phase==='countdown'){const left=Math.max(0,origin-sound.time);ink(...inkRGB);centered(write,String(Math.ceil(left)),Math.round(h/2-40),8,w);return;} if(!active)return; - const lyrics=cfg.lyrics||[],beat=60/(cfg.bpm||100); - // ---- headline: the lead line being sung, or the one still lingering - if(headCursor>0&&t<(lyrics[headCursor-1]?.t??0))headCursor=0; // a new run: rewind - let head=null,next=null; - for(let i=headCursor;i=l.t+l.dur+linger){headCursor=i+1;continue;} - if(t>=l.t-.3){head=l;for(let j=i+1;j=head.t&&t0&&t<(lyrics[humCursor-1]?.t??0))humCursor=0; - while(humCursor=lyrics[humCursor].t+lyrics[humCursor].dur))humCursor++; - let shown=0;const breathe=.5+.5*Math.max(0,1-((t/beat)%1)*1.4); - for(let i=humCursor;it)break;if(l.role!=='hum'||t>=l.t+l.dur)continue; - const size=2,x=Math.round(w*(.18+shown*.32)-textWidth(l.text,size)/2),y=h-40-Math.round(breathe*6); - ink(...(dark?[Math.round(bg[0]*.45),Math.round(bg[1]*.45),Math.round(bg[2]*.45)]:[Math.round(bg[0]*.5+80),Math.round(bg[1]*.5+80),Math.round(bg[2]*.5+80)])); - write(l.text,{x,y,font:FONT,size});shown++; - } + const lyrics=cfg.lyrics||[]; + while(wordCursor=lyrics[wordCursor].t+lyrics[wordCursor].dur+2.5)wordCursor++; + if(wordCursor>0&&tcur.t+cur.dur+linger)return; + const syls=cur.syllables||[];let sung=-1;for(let i=0;i