Eric's fireball lands as the house style — layered construction, gradient core, glow halo, a directional tail riding rotate="auto" — with its defs scoped per instance via $props.id(), so simultaneous fireballs cannot steal each other's gradients. The rest of the catalog is rebuilt in its image: the waterbolt becomes its cold sibling (spray tail, no turbulence — one heavy filter stack is enough); lightning grows a glowing core and branching forks; the burst blooms through a fire gradient with a shockwave and flying embers; the splash throws a crown of droplets; the shield raises a gradient dome with a rim strike; the pow star flashes white and radiates speed dashes; claws leave tapered gashes; the absorbed card spirals in along a pull ring; the soul is a proper little ghost with eyes, swaying as it rises; fireworks ride colored trails; Chaos catches card slips in its vortex; the pit opens a gradient hole that swallows a faller; ooze splats and flings blobs; the thornbush sheds leaves; slime closes over and pops bubbles; masonry dust goes soft with falling grit. Whiff, tacks, portal, and the sector ghosts keep their simpler forms on purpose — restraint is part of the style. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
51 lines
1.8 KiB
Svelte
51 lines
1.8 KiB
Svelte
<script lang="ts">
|
|
import type { FxOf } from "../fx";
|
|
import { CELL, center } from "./geom";
|
|
|
|
let { fx }: { fx: FxOf<"dust-puff" | "edge-dust"> } = $props();
|
|
const uid = $props.id();
|
|
const c = $derived.by(() => {
|
|
if (fx.kind === "dust-puff") return center(fx.at);
|
|
const mid = center(fx.cell);
|
|
if (fx.side === "N") return { x: mid.x, y: fx.cell.y * CELL };
|
|
if (fx.side === "S") return { x: mid.x, y: (fx.cell.y + 1) * CELL };
|
|
if (fx.side === "W") return { x: fx.cell.x * CELL, y: mid.y };
|
|
return { x: (fx.cell.x + 1) * CELL, y: mid.y };
|
|
});
|
|
</script>
|
|
|
|
<defs>
|
|
<radialGradient id={`dust-soft-${uid}`}>
|
|
<stop offset="0" stop-color="#b5a88e" stop-opacity="0.85" />
|
|
<stop offset="1" stop-color="#8d8266" stop-opacity="0" />
|
|
</radialGradient>
|
|
</defs>
|
|
|
|
<circle cx={c.x - 6} cy={c.y} r="6" fill={`url(#dust-soft-${uid})`} class="dust" />
|
|
<circle cx={c.x + 5} cy={c.y - 3} r="5" fill={`url(#dust-soft-${uid})`} class="dust late" />
|
|
<circle cx={c.x} cy={c.y + 4} r="5.5" fill={`url(#dust-soft-${uid})`} class="dust later" />
|
|
<g class="grit">
|
|
<circle cx={c.x - 4} cy={c.y - 5} r="1" />
|
|
<circle cx={c.x + 6} cy={c.y + 2} r="1.2" />
|
|
<circle cx={c.x + 1} cy={c.y - 2} r="0.8" />
|
|
</g>
|
|
|
|
<style>
|
|
.dust {
|
|
transform-box: fill-box;
|
|
transform-origin: center;
|
|
animation: drift 0.75s ease-out forwards;
|
|
}
|
|
.dust.late { animation-delay: 0.09s; }
|
|
.dust.later { animation-delay: 0.17s; }
|
|
.grit circle { fill: #6e6450; animation: grit-fall 0.6s ease-in forwards; }
|
|
@keyframes drift {
|
|
0% { opacity: 0.9; transform: translateY(0) scale(1); }
|
|
100% { opacity: 0; transform: translateY(-12px) scale(2); }
|
|
}
|
|
@keyframes grit-fall {
|
|
0% { opacity: 0.9; transform: translateY(-3px); }
|
|
100% { opacity: 0; transform: translateY(7px); }
|
|
}
|
|
</style>
|