@@ -26,8 +26,6 @@ let profile: Profile = loadProfileSync(); // instant boot from the mirror
2626// venue drives the scene; the real clock only grades it (day/night). ?venue= forces one for testing
2727const forcedVenue = new URLSearchParams ( location . search ) . get ( "venue" ) as VenueId | null ;
2828const currentVenue = ( ) : VenueId => ( forcedVenue && forcedVenue in VENUES ? forcedVenue : profile . venue ) ;
29- // Zen (calm) mode: hide the score/economy layer + drop all penalties. Default on.
30- const zen = ( ) : boolean => profile . settings . zen ;
3129
3230// ?weather=rain|snow|haze|clear forces the atmosphere (testing / manual)
3331type WeatherKind = "clear" | "rain" | "snow" | "haze" ;
@@ -67,7 +65,6 @@ function syncScene(): void {
6765 clock24 : profile . settings . clock24 , live : audio . playing ,
6866 } ) ;
6967 document . body . classList . toggle ( "no-scanlines" , ! profile . settings . scanlines ) ;
70- document . body . classList . toggle ( "zen" , zen ( ) ) ; // hides the dock cred/fans chip in CSS
7168 document . body . dataset . ui = profile . settings . uiScale ?? "m" ; // HUD size (drives --ui in CSS)
7269}
7370
@@ -108,7 +105,7 @@ const controls = new Controls($("controls"), profile, {
108105 persist ( ) ; controls . setProfile ( profile ) ; syncScene ( ) ;
109106 toast ( `🎉 ${ pz . name } unlocked!` ) ;
110107 } ,
111- onSettings : ( patch ) => { Object . assign ( profile . settings , patch ) ; persist ( ) ; syncScene ( ) ; syncClock ( ) ; if ( "zen" in patch ) controls . setProfile ( profile ) ; if ( " presenceMode" in patch ) void setPresence ( patch . presenceMode ! ) ; if ( "weatherAuto" in patch || "weatherCity" in patch ) void refreshWeather ( ) ; } ,
108+ onSettings : ( patch ) => { Object . assign ( profile . settings , patch ) ; persist ( ) ; syncScene ( ) ; syncClock ( ) ; if ( "presenceMode" in patch ) void setPresence ( patch . presenceMode ! ) ; if ( "weatherAuto" in patch || "weatherCity" in patch ) void refreshWeather ( ) ; } ,
112109 onSelectTrack : ( i ) => void audio . select ( i ) ,
113110 onAddFiles : ( ) => fileInput . click ( ) ,
114111 onAddStation : ( name : string , url : string , genre : Genre ) => tuneStation ( name , url , genre ) ,
@@ -239,23 +236,6 @@ venueName.onclick = () => openVenueBoard();
239236venueBoard . querySelector ( ".vb-scrim" ) ?. addEventListener ( "click" , closeVenueBoard ) ;
240237venueBoard . querySelector ( ".vb-close" ) ?. addEventListener ( "click" , closeVenueBoard ) ;
241238
242- // ── one-tap Game / Calm toggle — flips Zen (hides the game HUD for heads-down) ──
243- const modeToggle = $ ( "modeToggle" ) ;
244- function syncModeToggle ( ) : void {
245- modeToggle . textContent = zen ( ) ? "🌿" : "🎮" ;
246- modeToggle . title = zen ( ) ? "Calm view — tap for Game" : "Game view — tap for Calm" ;
247- }
248- modeToggle . onclick = ( e ) => {
249- e . stopPropagation ( ) ;
250- profile . settings . zen = ! profile . settings . zen ;
251- persist ( ) ;
252- syncScene ( ) ; // toggles body.zen → shows/hides buffs, Cred chip, desk counter
253- controls . setProfile ( profile ) ;
254- syncModeToggle ( ) ;
255- toast ( zen ( ) ? "🌿 Calm view" : "🎮 Game view" ) ;
256- } ;
257- syncModeToggle ( ) ;
258-
259239// ── 📱 QR → the phone REMOTE that controls this kiosk (/remote.html) ──────────
260240const qrBtn = $ ( "qrBtn" ) , qrOverlay = $ ( "qrOverlay" ) ;
261241let qrReady = false ;
@@ -293,7 +273,6 @@ function applyRemote(cmd: string, value: unknown): void {
293273 case "prev" : void audio . prev ( ) ; break ;
294274 case "volume" : if ( typeof value === "number" ) applyVolume ( Math . max ( 0 , Math . min ( 1 , value ) ) ) ; break ;
295275 case "mute" : audio . toggleMute ( ) ; syncMuteIcon ( ) ; controls . setTransport ( audio . playing , audio . muted ) ; break ;
296- case "mode" : profile . settings . zen = value === "calm" ; persist ( ) ; syncScene ( ) ; controls . setProfile ( profile ) ; syncModeToggle ( ) ; break ;
297276 case "buyVenue" : if ( typeof value === "string" && value in VENUES ) buyVenue ( value as VenueId ) ; break ;
298277 case "reloadLibrary" : void fetchLibrary ( ) . then ( ( lib ) => { if ( lib . length ) { audio . addTracks ( lib ) ; controls . setMedia ( audio . tracks , audio . index ) ; } } ) ; break ;
299278 case "restoreProfile" : void restoreProfile ( value ) ; break ;
@@ -324,7 +303,7 @@ function reportState(): void {
324303 profileId : profile . id , // lets the companion fetch the full profile for backup
325304 trackIndex : audio . index , trackTitle : c ?. title ?? null ,
326305 playing : audio . playing , muted : audio . muted , volume : profile . settings . volume ,
327- mode : zen ( ) ? "calm" : "game" , unlocks : profile . unlocks , cred : Math . floor ( profile . cred ) ,
306+ mode : "game" , unlocks : profile . unlocks , cred : Math . floor ( profile . cred ) ,
328307 tracks : audio . tracks . map ( ( t , i ) => ( { i, title : t . title , artist : t . artist , station : ! ! t . station } ) ) ,
329308 } ) ,
330309 } ) . catch ( ( ) => { } ) ;
@@ -375,7 +354,7 @@ function fanPost(): void {
375354 setTimeout ( ( ) => { card . classList . add ( "out" ) ; setTimeout ( ( ) => card . remove ( ) , 600 ) ; } , 7000 ) ;
376355}
377356( function scheduleFan ( ) {
378- setTimeout ( ( ) => { if ( ! zen ( ) && audio . playing ) fanPost ( ) ; scheduleFan ( ) ; } , ( 20 + Math . random ( ) * 18 ) * 1000 ) ;
357+ setTimeout ( ( ) => { if ( audio . playing ) fanPost ( ) ; scheduleFan ( ) ; } , ( 20 + Math . random ( ) * 18 ) * 1000 ) ;
379358} ) ( ) ;
380359
381360// ── curfew gag: linger at an outdoor venue after dark → 🚓 the cops show up ────
@@ -400,7 +379,7 @@ function curfewBlock(id: VenueId): boolean {
400379}
401380function updateCurfew ( dt : number ) : void {
402381 if ( ! curfewHour ( ) && busted . size ) busted . clear ( ) ; // dawn — the raided spots reopen
403- if ( copsActive || zen ( ) ) return ; // a Game-mode gag — never interrupts Calm/focus
382+ if ( copsActive ) return ; // don't stack a second raid while one's playing out
404383 const v = currentVenue ( ) ;
405384 if ( VENUES [ v ] . curfew && curfewHour ( ) && ( presence . current . present || audio . playing ) ) {
406385 curfewMs += dt ;
@@ -428,20 +407,19 @@ function triggerCops(): void {
428407// beacon after dark, and the cops countdown on the board while it's running
429408function syncCurfewSign ( ) : void {
430409 const v = currentVenue ( ) ;
431- if ( zen ( ) || ! VENUES [ v ] . curfew ) { scene . setCurfew ( null ) ; return ; }
410+ if ( ! VENUES [ v ] . curfew ) { scene . setCurfew ( null ) ; return ; }
432411 const night = curfewHour ( ) ;
433412 const remain = night && curfewMs > 0
434413 ? Math . max ( 0 , Math . ceil ( ( CURFEW . lingerSec * 1000 * FAST - curfewMs ) / 1000 ) )
435414 : null ;
436415 scene . setCurfew ( { night, remainSec : remain } ) ;
437416}
438417// break warning — the healthy counterpart to the cops: a prominent, escalating
439- // nudge (heads-up → pulsing "BREAK TIME") once a focus block lands. Game-mode
440- // only; Calm mode keeps the quiet deskTimer nudge.
418+ // nudge (heads-up → pulsing "BREAK TIME") once a focus block lands.
441419function renderBreakSign ( ) : void {
442420 const present = presence . active ? presence . current . present : audio . playing ;
443421 let state = "" ;
444- if ( ! zen ( ) && present && ! onBreak ) {
422+ if ( present && ! onBreak ) {
445423 if ( breakDue ) state = "due" ;
446424 else if ( focusMs > 0 && FOCUS_MS - focusMs <= SOON_MS ) state = "soon" ;
447425 }
@@ -457,9 +435,8 @@ function renderBreakSign(): void {
457435 + `<span class="cs-txt">a good stopping point in ${ fmtDuration ( Math . max ( 0 , FOCUS_MS - focusMs ) ) } </span>` ;
458436 }
459437}
460- // a brief teal "you earned it" flash when a block first completes (Game mode)
438+ // a brief teal "you earned it" flash when a block first completes
461439function triggerBreak ( ) : void {
462- if ( zen ( ) ) return ;
463440 breakFlash . classList . add ( "on" ) ;
464441 setTimeout ( ( ) => breakFlash . classList . remove ( "on" ) , 2800 ) ;
465442}
@@ -1067,11 +1044,9 @@ setInterval(() => {
10671044 updateNowPlaying ( ) ;
10681045 if ( ++ persistTick >= 20 ) { persistTick = 0 ; persist ( ) ; } // checkpoint the log ~every 20s
10691046 const todayMs = deskTotals ( profile ) . today * 1000 ;
1070- // Zen: the desk timer only surfaces for the gentle break nudge — no always-on
1071- // session counter to glance at.
10721047 // keep the session timer on screen through an active session (or while music plays)
10731048 // so a glance at your main monitor doesn't make it vanish + read as a reset
1074- deskTimer . classList . toggle ( "on" , breakDue || ( ! zen ( ) && ( presence . current . present || focusMs > 0 || audio . playing ) ) ) ;
1049+ deskTimer . classList . toggle ( "on" , breakDue || presence . current . present || focusMs > 0 || audio . playing ) ;
10751050 deskTimer . classList . toggle ( "break" , breakDue ) ;
10761051 const atDesk = presence . active ? presence . current . present : audio . playing ;
10771052 deskTimer . innerHTML = breakDue && ! atDesk
0 commit comments