The fireball sets the bar, and the rest of the catalog rises to it
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>
This commit is contained in:
co-authored by
Claude Fable 5
parent
fe0318b99b
commit
308f1b6ff9
@@ -1,26 +1,55 @@
|
||||
<script lang="ts">
|
||||
import type { FxOf } from "../fx";
|
||||
import { center } from "./geom";
|
||||
|
||||
let { fx }: { fx: FxOf<"fireworks"> } = $props();
|
||||
const c = $derived(center(fx.at));
|
||||
const COLORS = ["#e74c3c", "#f1c40f", "#3b8dd6", "#7ac47e"];
|
||||
const RAYS = [0, 45, 90, 135, 180, 225, 270, 315];
|
||||
</script>
|
||||
|
||||
<g class="fireworks" style={`transform-origin: ${c.x}px ${c.y}px`}>
|
||||
{#each [0, 45, 90, 135, 180, 225, 270, 315] as deg (deg)}
|
||||
<g class="fireworks">
|
||||
{#each RAYS as deg, i (deg)}
|
||||
{@const dx = Math.cos((deg * Math.PI) / 180)}
|
||||
{@const dy = Math.sin((deg * Math.PI) / 180)}
|
||||
<line
|
||||
x1={c.x + 4 * dx} y1={c.y + 4 * dy}
|
||||
x2={c.x + 20 * dx} y2={c.y + 20 * dy}
|
||||
stroke={COLORS[i % 4]}
|
||||
class="trail"
|
||||
style={`transform-origin: ${c.x}px ${c.y}px`}
|
||||
/>
|
||||
<circle
|
||||
cx={c.x + 18 * Math.cos((deg * Math.PI) / 180)}
|
||||
cy={c.y + 18 * Math.sin((deg * Math.PI) / 180)}
|
||||
r="3" fill={COLORS[(deg / 45) % 4]}
|
||||
cx={c.x + 21 * dx} cy={c.y + 21 * dy} r="2.6"
|
||||
fill={COLORS[i % 4]}
|
||||
class="spark"
|
||||
style={`transform-origin: ${c.x}px ${c.y}px`}
|
||||
/>
|
||||
{/each}
|
||||
<circle cx={c.x} cy={c.y} r="3.5" class="heart" />
|
||||
</g>
|
||||
|
||||
<style>
|
||||
.fireworks { animation: boom 1.1s ease-out forwards; }
|
||||
@keyframes boom {
|
||||
0% { opacity: 0; transform: scale(0.1); }
|
||||
.trail {
|
||||
stroke-width: 2;
|
||||
stroke-linecap: round;
|
||||
animation: trail-out 0.9s ease-out forwards;
|
||||
}
|
||||
.spark { animation: spark-out 1.05s ease-out forwards; }
|
||||
.heart { fill: #fffdf0; animation: heart-pop 0.4s ease-out forwards; }
|
||||
@keyframes trail-out {
|
||||
0% { opacity: 0; transform: scale(0.15); }
|
||||
25% { opacity: 1; }
|
||||
100% { opacity: 0; transform: scale(2.4) rotate(30deg); }
|
||||
100% { opacity: 0; transform: scale(1.5); }
|
||||
}
|
||||
@keyframes spark-out {
|
||||
0% { opacity: 0; transform: scale(0.15); }
|
||||
30% { opacity: 1; }
|
||||
80% { opacity: 0.9; transform: scale(1.55); }
|
||||
100% { opacity: 0; transform: scale(1.6) translateY(4px); }
|
||||
}
|
||||
@keyframes heart-pop {
|
||||
0% { opacity: 1; transform: scale(0.5); }
|
||||
100% { opacity: 0; transform: scale(3); }
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user