fix: refactor store to singleton class pattern (s.subscribe fix)
All checks were successful
CI/CD — Build & Deploy / Build & Deploy (push) Successful in 21s

Exported $state proxies were confused with Svelte stores by SvelteKit
runtime, causing "s.subscribe is not a function" on /jeu.

Fix: encapsulate all $state fields in a Game class, export singleton.
Components import { game } and access game.state, game.click(), etc.
Class fields are proper $state — no raw proxy exported.
This commit is contained in:
2026-03-28 20:39:21 +01:00
parent cce7fa3190
commit 67931eeadb
16 changed files with 277 additions and 325 deletions

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { fly, scale, fade } from 'svelte/transition';
import { quintOut, backOut } from 'svelte/easing';
import { state, refs, prestige, closePrestige } from '$lib/stores/game.svelte';
import { game } from '$lib/stores/game.svelte';
import { computePrestigeDna, getPrestigeDnaBonus, getPrestigeThreshold } from '$lib/core/economy';
import { formatNumber } from '$lib/utils/formatNumber';
@@ -15,24 +15,24 @@
return `${seconds}s`;
}
let baseDna = $derived(computePrestigeDna(state.lifetimeTadpoles, state.prestigeCount));
let dnaBonus = $derived(getPrestigeDnaBonus(state.evolutionTree));
let baseDna = $derived(computePrestigeDna(game.game.state.lifetimeTadpoles, game.game.state.prestigeCount));
let dnaBonus = $derived(getPrestigeDnaBonus(game.state.evolutionTree));
let dnaPreview = $derived(Math.floor(baseDna * (1 + dnaBonus)));
let threshold = $derived(getPrestigeThreshold(state));
let canPrestige = $derived(state.lifetimeTadpoles >= threshold);
let runDuration = $derived(Date.now() - state.runStats.startedAt);
let bestRun = $derived(state.runStats.bestRun);
let threshold = $derived(getPrestigeThreshold(game.state));
let canPrestige = $derived(game.game.state.lifetimeTadpoles >= threshold);
let runDuration = $derived(Date.now() - game.state.runStats.startedAt);
let bestRun = $derived(game.state.runStats.bestRun);
let isBestAdn = $derived(!bestRun || dnaPreview > bestRun.adn);
let isBestTadpoles = $derived(!bestRun || state.lifetimeTadpoles > bestRun.tadpoles);
let isBestTadpoles = $derived(!bestRun || game.game.state.lifetimeTadpoles > bestRun.tadpoles);
function handlePrestige() {
if (canPrestige) prestige();
if (canPrestige) game.prestige();
}
</script>
<svelte:window onkeydown={(e) => { if (e.key === 'Escape' && refs.showPrestigeScreen) closePrestige(); }} />
<svelte:window onkeydown={(e) => { if (e.key === 'Escape' && game.showPrestigeScreen) game.game.closePrestige(); }} />
{#if refs.showPrestigeScreen}
{#if game.showPrestigeScreen}
<!-- Backdrop -->
<div
class="fixed inset-0 z-50 flex items-center justify-center"
@@ -48,7 +48,7 @@
<!-- Header with generation number -->
<div class="text-center" in:fly={{ y: -20, delay: 100, duration: 400, easing: quintOut }}>
<span class="gp-title text-lg!">Nouvelle Generation</span>
<p class="gp-label mt-1">Generation #{state.prestigeCount + 1}</p>
<p class="gp-label mt-1">Generation #{game.state.prestigeCount + 1}</p>
</div>
<div class="gp-sep"></div>
@@ -68,7 +68,7 @@
{#if dnaBonus > 0}
<span class="gp-label">(base {formatNumber(baseDna)} + {Math.round(dnaBonus * 100)}% arbre)</span>
{/if}
<span class="gp-label mt-1">Total apres : {formatNumber(state.ancestralDna + dnaPreview)} ADN</span>
<span class="gp-label mt-1">Total apres : {formatNumber(game.state.ancestralDna + dnaPreview)} ADN</span>
</div>
<div class="gp-sep"></div>
@@ -85,7 +85,7 @@
<div class="flex justify-between">
<span class="gp-label">Tetards produits</span>
<span class="gp-value {isBestTadpoles ? 'gp-accent-green' : ''}">
{formatNumber(state.lifetimeTadpoles)}
{formatNumber(game.state.lifetimeTadpoles)}
{#if isBestTadpoles && bestRun}{/if}
</span>
</div>
@@ -141,7 +141,7 @@
<!-- Actions -->
<div class="flex gap-2 mt-1" in:fly={{ y: 20, delay: 450, duration: 300, easing: quintOut }}>
<button
onclick={() => closePrestige()}
onclick={() => game.closePrestige()}
class="gp-btn flex-1 py-2.5! text-[0.8rem]!"
style="background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.6);"
>
@@ -153,7 +153,7 @@
</button>
{:else}
<button class="gp-btn gp-btn--disabled flex-1 py-2.5!" disabled>
{formatNumber(threshold - state.lifetimeTadpoles)} manquants
{formatNumber(threshold - game.state.lifetimeTadpoles)} manquants
</button>
{/if}
</div>