8.8 KiB
Web-/lydgennemgang: pony-frontend
Genereret med web-games-pluginets web-optimization-checklist- og web-audio-specialist-skabeloner, tilpasset til den faktiske kode i pony-frontend/ (Create React App 5 / react-scripts, React 19, framer-motion) i stedet for at gengive den generiske tjekliste ukritisk.
Lydarkitektur: pony-frontend
Lydoversigt
Lydkontekst: Én delt AudioContext via singleton'en AudioManager i SceneMusic.js — korrekt arkitektur (matcher "single context, multiple channels"-princippet).
Kanaler: masterGain → musicGain + sfxGain, med volumen persisteret i localStorage (pony_music_vol, pony_sfx_vol, pony_muted).
Format-strategi: Ingen lydfiler overhovedet — al lyd (musik og SFX) genereres proceduralt med oscillatorer (createOscillator/createBiquadFilter). Det betyder, at store dele af den generiske "asset-optimering"-tjekliste (MP3/OGG-formater, komprimering, audio sprites, streaming) simpelthen ikke er relevant her — der er 0 KB lyd-assets at optimere.
Fund (specifikt for denne kode)
1. SoundFX.js er dødt/duplikeret kode
SoundFX.js genimplementerer nøjagtig de samme funktioner (playClick, playRoll, playSuccess, playFail, playSelect, playVictory) som allerede eksporteres fra SceneMusic.js — men med sin egen rå AudioContext forbundet direkte til ctx.destination, uden om AudioManagers gain-struktur. App.js importerer udelukkende fra ./SceneMusic, så SoundFX.js ser ud til aldrig at blive brugt.
Konsekvens: Hvis filen nogensinde importeres ved en fejl (fx under en refaktorering), vil de lyde, den afspiller, ignorere spillerens lydstyrke- og mute-indstillinger, fordi de ikke går gennem sfxGain/masterGain.
Anbefaling: Slet SoundFX.js. Det er ren dødvægt og en fælde for fremtidige imports.
2. Kun musik-lydstyrke er justerbar i UI'en
AudioManager understøtter separate musicGain/sfxGain-kanaler, men VolumeControl.js kalder kun setMasterVolume(v), som mapper til setMusicVolume (se kommentaren "Backward-compatible master volume (maps to music)" i SceneMusic.js:195-199). SFX-lydstyrken er derfor låst til sin localStorage-standardværdi (0.7) eller sidst gemte værdi og kan ikke justeres fra UI'en, selvom infrastrukturen til det allerede findes.
Anbefaling: Enten tilføj en synlig SFX-lydstyrkeknap, eller — hvis én samlet skyder er et bevidst UX-valg for målgruppen (børn) — lad VolumeControl kalde både setMusicVolume og setSfxVolume, så "mute" reelt slukker alt, ikke kun musikken.
3. Ingen håndtering af faneskift/afbrydelse
SceneMusic lytter ikke til document.visibilitychange eller AudioContexts statechange-event. Musikken (drevet af setInterval(playMelody, …) og setInterval(playPad, 8000)) fortsætter med at planlægge noder, selv når fanen er skjult, hvilket spilder CPU/batteri på mobil og kan give en pludselig lydbrag, når man vender tilbage til fanen, hvis flere planlagte noder er stablet op.
Anbefaling: Suspendér AudioContext ved document.hidden og genoptag ved synlighed (standardmønster, se f.eks. iOS Safari-afbrydelseshåndtering).
4. manifest.json er stadig CRA's standardskabelon
public/manifest.json indeholder stadig "short_name": "React App" og "name": "Create React App Sample" — den er aldrig tilpasset til spillet. theme_color er sort og background_color hvid, uden sammenhæng med spillets faktiske farvepalet.
Anbefaling: Udfyld navn, kort navn, temafarve og ikoner, hvis siden nogensinde skal kunne installeres som PWA (se punkt 5).
5. Ingen service worker / ingen reel PWA
Der er intet service worker-register i src/index.js, og reportWebVitals.js er den eneste "extra" fra CRA-skabelonen. Appen er reelt en almindelig SPA uden offline-understøttelse eller cache-first-indlæsning, selvom manifest.json antyder PWA-hensigt.
Anbefaling: Enten fjern PWA-artefakterne helt for at undgå at love noget, siden ikke leverer, eller tilføj CRA's indbyggede serviceWorkerRegistration (kræver at skifte fra register()/unregister()-boilerplaten, som CRA 5 stadig leverer som opt-in).
6. Ubrugt asset-mappe
public/music/ eksisterer, men er tom — sandsynligvis en rest fra en tidligere plan om at bruge indspillede lydfiler, før musikken blev lagt om til proceduralt genereret lyd.
Anbefaling: Fjern den tomme mappe, eller dokumentér hvorfor den er der, hvis den er tiltænkt fremtidig brug.
Platformovervejelser
Mobilhåndtering
- Brugerinteraktions-oplåsning: Håndteres korrekt —
App.jsviser en eksplicit "Aktivér lyd"-prompt (enableSound→resumeAudioContext()), som overholder browsernes autoplay-politik. - Afbrydelseshåndtering: Mangler (se fund #3).
- Baggrundslyd: Ikke defineret opførsel — bør besluttes bevidst (se fund #3).
Browserkompatibilitet
| Funktion | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
| Web Audio API | ✓ | ✓ | ✓ | ✓ |
BiquadFilterNode (bruges i playPad) |
✓ | ✓ | ✓ | ✓ |
webkitAudioContext-fallback |
✓ (ikke nødvendig) | ✓ (ikke nødvendig) | Understøttet i AudioManager.init() — god praksis |
✓ |
Optimeringstjekliste til weblansering: pony-frontend
Tilpasset til det, der faktisk er relevant for et CRA/React 19/framer-motion-projekt uden lydfiler eller WebGL.
Build-optimering
- Kør
npm run buildog inspicér output medsource-map-explorerellerreact-scripts-standard bundle-rapporten —framer-motioner et relativt tungt afhængighed, og det er værd at bekræfte, at kun de nødvendige dele importeres. - Overvej om Create React App (react-scripts 5, i praksis uvedligeholdt siden 2023) fortsat er det rette byggeværktøj, eller om en migrering til Vite ville reducere build-tid og bundle-størrelse — dette er en større beslutning og ikke noget, der skal gøres uden en eksplicit vurdering.
- CSS er allerede organiseret i design-tokens (jf. tidligere CSS-refaktorering) — bekræft at ubrugt CSS ikke akkumuleres, efterhånden som komponenter fjernes.
Asset-optimering
- Lyd: Ikke relevant — al lyd er proceduralt genereret, 0 KB lydassets.
- Billeder: Ponybilleder (
data.ponyImg, hentet fra backend'en via${API}${data.ponyImg}) bør tjekkes for komprimering og passende opløsning — dette ligger iweb/-backend'en, ikke i frontend-repoet, og er ikke gennemgået her. - Fonte: Ingen brugerdefinerede web-fonte fundet i de gennemgåede filer — bekræft i
index.css/App.cssom systemfonte bruges (billigst) eller om der indlæses eksterne fonte, der bør subsettes.
Runtime-ydeevne
SceneMusicssetInterval-baserede node-planlægning (fund #3) bør profileres på en lav-effekt mobilenhed for at bekræfte, at det ikke giver mærkbare hak iframer-motion-animationerne, som kører samtidig på samme hovedtråd.- Bekræft, at
activeNodesRef/activeNodes-oprydningen iAudioManager.scheduleNoterent faktisk forhindrer akkumulering af oscillator-noder over en lang spilsession (koden ser korrekt ud ved gennemlæsning, men bør verificeres i praksis over 10+ minutters kørsel).
Indlæsningsydeevne
- Mål First Contentful Paint / Time to Interactive med Lighthouse — ingen eksisterende måling er fundet i repoet.
api.loadContent()kaldes ved opstart og har en fallback tilDEFAULT_PONIES, hvis backend'en fejler (god praksis) — bekræft at brugeren ser en meningsfuld loading-tilstand, mens dette kald er undervejs (ser ud til at være tilfældet vialoading-state iApp.js).
Mobiloptimering
- Berøringsmål: "🎲 KAST TERNINGERNE!"-knappen og navigationsknapperne bør måles for at bekræfte ≥48px berøringsflade, særligt for målgruppen (børn, som ofte har mindre præcis finger-styring).
- Bekræft responsivt layout på faktiske mobilskærme — ikke verificeret i denne gennemgang (kræver visuel test, se anbefaling nedenfor).
PWA-tjekliste
manifest.jsoner ikke udfyldt korrekt (fund #4) — enten ret det op, eller fjern PWA-ambitionen bevidst.- Ingen service worker registreret (fund #5).
Før lancering
- Kør browserkonsollen igennem for fejl/advarsler på alle sider (Home, Theme, PonySelect, GameScene, GameEnd).
- Bekræft at
SoundFX.jsfjernes, så det ikke ved en fejl importeres senere (fund #1).
Ydeevnebudget
| Metrik | Budget | Status |
|---|---|---|
| Lyd-assets (KB) | 0 (proceduralt) | ✓ Opfyldt af design |
| Berøringsmål | ≥48px | Ikke målt i denne gennemgang |
| Initial indlæsning | <3s Time to Interactive | Ikke målt — kræver Lighthouse-kørsel i browser |
Bemærkning om dækning: Denne gennemgang er baseret på statisk kodelæsning, ikke en kørende måling i browseren (ingen Lighthouse-/DevTools-profil er kørt). Punkterne markeret "Ikke målt" bør verificeres ved faktisk at køre appen, før de afkrydses.