All checks were successful
CI/CD — Build & Deploy / Build & Deploy (push) Successful in 22s
Core logic portable (economy, balance, cosmetics, migrateSave) — zero rewrite. 136 tests green, identiques. Backend inchangé. - Svelte 5 runes stores (game, auth, toast) remplacent Zustand - SvelteKit adapter-static SPA (dist/ output, fallback index.html) - Tailwind v4 conservé, design system .gp-* porté - Transitions natives : slide, fly, scale, fade sur toute l'UI - Sidebar tabbée (Production/Evolution/Collection) + CollapsiblePanel - Mobile bottom sheet avec FAB toggle + backdrop blur - Click particles réactifs Svelte (plus de DOM impératif) - TadpoleSprite bounce + glow ring au clic - Guide refait en accordéon, Achievements avec filtres - a11y : focus-visible, Escape modals, aria-current, aria-labels - CI/CD adapté (tests + build + rsync) - Build 504K (vs ~1.2MB React)
51 lines
1.4 KiB
Svelte
51 lines
1.4 KiB
Svelte
<script lang="ts">
|
|
import { fly, fade } from 'svelte/transition';
|
|
import { quintOut } from 'svelte/easing';
|
|
import { formatNumber } from '$lib/utils/formatNumber';
|
|
|
|
interface Particle {
|
|
id: number;
|
|
x: number;
|
|
y: number;
|
|
gain: number;
|
|
isDouble: boolean;
|
|
isCrit: boolean;
|
|
}
|
|
|
|
let particles = $state<Particle[]>([]);
|
|
let nextId = 0;
|
|
|
|
export function spawn(x: number, y: number, gain: number, isDouble: boolean, isCrit: boolean) {
|
|
const id = nextId++;
|
|
// Random horizontal spread
|
|
const offsetX = (Math.random() - 0.5) * 40;
|
|
particles = [...particles, { id, x: x + offsetX, y, gain, isDouble, isCrit }];
|
|
setTimeout(() => {
|
|
particles = particles.filter(p => p.id !== id);
|
|
}, 1000);
|
|
}
|
|
</script>
|
|
|
|
<div class="fixed inset-0 pointer-events-none z-[100]">
|
|
{#each particles as p (p.id)}
|
|
{@const prefix = p.isCrit ? 'CRIT ' : p.isDouble ? 'x2 ' : ''}
|
|
{@const color = p.isCrit ? '#f59e0b' : p.isDouble ? '#a78bfa' : '#34d399'}
|
|
{@const size = p.isCrit ? '2rem' : p.isDouble ? '1.8rem' : '1.6rem'}
|
|
<span
|
|
class="absolute font-extrabold"
|
|
style="
|
|
left: {p.x}px;
|
|
top: {p.y}px;
|
|
color: {color};
|
|
font-size: {size};
|
|
font-family: var(--font);
|
|
text-shadow: 0 0 10px {color}60, 0 2px 6px rgba(0,0,0,0.7);
|
|
"
|
|
in:fly={{ y: 0, duration: 50 }}
|
|
out:fly={{ y: -90, duration: 900, easing: quintOut, opacity: 0 }}
|
|
>
|
|
{prefix}+{formatNumber(p.gain)}
|
|
</span>
|
|
{/each}
|
|
</div>
|