Commit Graph

8 Commits

Author SHA1 Message Date
Claude Agent
d8cb515545 Muzica ambient T10: arpegiu calm care accelereaza sub 1 min
Opt-in din builder (checkbox music, default off). Orchestrator-only: parintele
detine AudioContext (reutilizeaza beep._ctx); camerele nu stiu de muzica.

- arpegiu pentatonica minora (oscilatoare sine scurte), tempo ~1.8x pe ultimul
  minut (legat de _deadline-ul Timer Calm); fara timer -> loop calm fara accelerare
- buton 🎵/🔇 in bara chrome (#btn-music)
- duck pe voce: voiceSay onstart/onend regleaza gain (vocea are prioritate)
- fallback fara AudioContext -> no-op, buton ascuns (zero penalizare)
- porneste la start + resume; stop la showFinale + toggle
- hook test window.__music; exemplu-campanie.html regenerat (ramane opt-in off)

Smoke 30/30 (test nou "muzica ambient": opt-in, start, tempo sub 1 min, duck, toggle).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 20:12:32 +00:00
Claude Agent
b359bbe50a Timer Calm (T10 / §Design pct.10): ceas campanie opt-in
Ceas M:SS in bara chrome a campaniei. Opt-in din builder (camp "Timp limita
(minute)", default 0 = fara; cleanState coerce 0..120).

- porneste exact la "Incepe aventura" (intro necronometrat)
- deadline ABSOLUT in sessionStorage -> resume nu reseteaza ceasul
- sub 1 min -> auriu (.low); expirare -> ingheata 0:00 + marcaj discret
  (.expired), jocul curge nestingherit (zero penalizare, stelele raman)
- fara rosu pulsant (public copii) -> reduced-motion safe by default
- exemplu-campanie.html regenerat (ramane fara timer - opt-in, ca vocea)

Fundatie pentru muzica T10 (accelerare sub 1 min) + footer diploma.
Test nou (smoke 29/29): format M:SS, prag auriu, freeze la expirare,
jocul continua dupa expirare, resume pastreaza ceasul.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 20:06:36 +00:00
Claude Agent
a30441eb03 PR2: audit a11y - reduced-motion, tap>=44px, aria pe progres+dpad
Audit faptic (masurat) pe 5 motoare + campanie. Deja OK din restyle S3:
tap targets (arcade 56x52, classic 44/48, chat 44), contrast (terminal .dim
9.4:1, classic hint 6:1), focus/keyboard (butoane reale, navigare cu sageti).

Reparat:
- reduced-motion (lacune): .confetti display:none in classic + SNIP.baseCss +
  campanie; flipin final in SNIP.finalCss (#fOverlay .fword span) + campanie
  (#fin-word span); dt-blink in campanie. (pop/flip/shake/bin/tile-pop/tp/
  door-glow/crt-flicker erau deja acoperite.) flipin/pop au 'backwards' fill ->
  animation:none le revine la starea vizibila, nu raman ascunse.
- tap: overworld dpad 42x42 -> 44x44 (singura tinta sub prag).
- aria: #dots role=group+label; fiecare dot role=img cu aria-label ce reflecta
  starea (neinceputa/in curs/rezolvata) via setDot; dpad arcade+overworld cu
  aria-label (Sus/Jos/Stanga/Dreapta/Pune bomba); spacere .sp aria-hidden.

Test nou smoke #9c (emulateMedia reducedMotion -> confetti display:none;
tap>=44px pe dpad; aria dinamic pe dots). 26/26. Demo-uri regenerate (terminal
neatins - nu foloseste SNIP base/final).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 12:04:55 +00:00
Claude Agent
ab11089097 PR2: unifica contractul _campaign la final in libJS.campaignDone()
Payload-ul parent.nextRoom({idx,stars,letter}) era scris identic in 3 locuri
(terminal finale(), SNIP.finalJs showFinal(), classic next()). Acum traieste o
singura data in libJS.campaignDone(), langa roomReady/beep/onerror.

Decizie: NU am pus terminalul pe showFinal() din SNIP (cum sugera formularea
initiala) — showFinal randeaza modal #fOverlay, dar terminalul are finale CRT
stilizat (ASCII 'EVADARE REUSITA' + RESTART), on-theme intentionat. Fortarea
modalului ar fi regresie vizuala pe terminalul standalone. Am unificat doar
ramura _campaign (payload identic), prezentarea standalone neatinsa.

- terminal finale(): say([...], 'ok', campaignDone)
- SNIP.finalJs showFinal(): if(_campaign){ campaignDone(); return; }
- arcade/chat/point primesc campaignDone via showFinal automat.
- classic ramane bespoke (nu foloseste libJS) — pliere = D7 (documentat in TODOS).

Suita 25/25 (terminal standalone + camere terminal in campanie E2E). Demo-uri
libJS regenerate; exemplu-clasic.html neatins.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 11:53:37 +00:00
Claude Agent
da93d8498c PR2: naratiune vocala (SpeechSynthesis, D10) - opt-in din builder
Feature nou (vocea nu exista deloc). Opt-in via checkbox 'voice' in builder
(off implicit), buton toggle in bara chrome a campaniei (parintele detine).
Voicing orchestrator-only, uniform pe toate 5 motoarele (fara dublu-citit):
povestea la 'Incepe aventura', intrebarea camerei la roomReady, mesajul final.

Edge cases (toate tratate):
- getVoices() gol sincron -> re-citire la onvoiceschanged.
- fara voce ro-* -> vocea default a sistemului (doar u.lang='ro-RO').
- speechSynthesis.cancel() in hideAll() -> fara replici fantoma la schimbarea scenei.
- fara 'speechSynthesis' in window -> buton ascuns, totul no-op.
- window.voiceSay expus pe parinte pt. viitor (replici motoare cu guard typeof).

Bug prins de test: #btn-voice{display:inline-flex} batea UA [hidden] ->
adaugat #btn-voice[hidden]{display:none}.

Test nou smoke #9b (voce opt-in: buton, citeste poveste/intrebare, cancel,
toggle) + asertare buton-ascuns cand voice=false. Suita 25/25. Demo regenerat.
AGENTS.md/TODOS actualizate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 11:46:33 +00:00
Claude Agent
651025bd28 S1 fix real: deblocare audio pe primul gest (acopera resume), nu doar btn-start
Fix-ul initial deblocà AudioContext-ul doar in handlerul btn-start. Lacuna:
calea de resume (reload mid-campanie) intra direct pe harta fara btn-start ->
ctx nedeblocat -> camere mute. Plus resume() singur nu ajunge pe iOS Safari.

- unlockAudio() + listener global one-time (pointerdown+keydown capture):
  acopera fresh SI resume; buffer silentios iOS-safe.
- beep() se auto-vindeca daca ctx redevine suspended.
- Test smoke #9 rescris: headless creeaza ctx direct 'running' (ignora autoplay)
  -> vechiul "ctx running" trecea trivial. Acum: gest tastatura fara btn-start
  -> running (cale resume) + beep self-heal din ctx suspendat.
- Demo campanie regenerat. Suita 24/24.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 11:29:21 +00:00
Claude Agent
463e3cc9bd regenereaza exemplu-campanie.html cu overworld + restyle
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 11:07:12 +00:00
Claude Agent
a4b0ff4154 Campanie multi-stil — PR1 (T1-T8 + TD1-TD6)
Adauga al 6-lea stil de joc: campanie multi-stil care leaga puzzle-urile
in camere de stiluri diferite (clasic/terminal/arcade/chat/point in rotatie),
conectate prin coridoare cu usa, litera si stele.

Contract de montare (verificat la gate T1):
- gameCampaign: un <iframe srcdoc> per camera; camerele cheama parent.*
  pe un nivel (merge si pe file://); template per stil cu sentinel __CFG__
  injectat prin replace-functie (D1) + json.replace(/</g,'<') (D6)
- roomReady/roomError + timeout 4s -> skip cu 0 stele + cod eroare;
  idx detinut de parinte, accepta nextRoom doar de la contentWindow activ (D5)
- parent.beep in mod campanie (un singur AudioContext, D2)
- resume prin safeStore try/catch (D3) + cheie djb2 peste CFG embedat (D11)

Builder:
- selector de stil per puzzle ("Auto (stil)") + optiunea Campanie multi-stil
- normalizePuzzle() la load + import (sursa unica pt forma puzzle, D8)
- blocare export+preview la 0 puzzle-uri; persist() guarded (D12)
- letter normalizat [A-Za-z0-9] + esc la SVG point (D13)

Design (DESIGN.md): tokens --c-*, intro poster, coridor "usa ca erou",
chrome unica sursa de progres, 5 usi CSS/SVG (normal/stuck/crescendo),
mod camera per motor, buget vertical mobil, baseline a11y.

Tooling: tests/smoke.mjs (Playwright, zero-dependente prin npx), TODOS.md,
sectiune ## Testing in CLAUDE.md. Demo-uri regenerate + exemplu-campanie.html.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 08:34:57 +00:00