Projectiles flew cell-center to cell-center, launching from the caster's feet and landing under the target's chin — tokens sit high in their squares and fan sideways when crowded. Every travelling effect (fireball, waterbolt, bolt, streak, and the reflection's return flight) now resolves token anchors that mirror the board's exact positioning, fan-out included: caster's center to target's center, wizard or creature. Spots with no token to aim at fall back to sensible cell points, and wash/knockback streaks end on the carried wizard wherever they fanned to. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
43 lines
1.3 KiB
Svelte
43 lines
1.3 KiB
Svelte
<script lang="ts">
|
|
import type { FxOf } from "../fx";
|
|
|
|
let { fx }: { fx: FxOf<"streak"> } = $props();
|
|
const a = $derived(fx.a);
|
|
const b = $derived(fx.b);
|
|
const d = $derived(`M ${a.x} ${a.y} L ${b.x} ${b.y}`);
|
|
</script>
|
|
|
|
<path {d} pathLength="100" class="trail wide" />
|
|
<path {d} pathLength="100" class="trail bright" />
|
|
<circle r="4" class="head" cx="0" cy="0">
|
|
<animateMotion dur="0.38s" fill="freeze" path={d} calcMode="spline"
|
|
keySplines="0.3 0 0.4 1" keyTimes="0;1" keyPoints="0;1" />
|
|
</circle>
|
|
|
|
<style>
|
|
.trail {
|
|
fill: none;
|
|
stroke-linecap: round;
|
|
stroke-dasharray: 100 100;
|
|
animation: draw-collapse 0.68s ease-out forwards;
|
|
}
|
|
.trail.wide { stroke: rgba(233, 225, 203, 0.3); stroke-width: 5; }
|
|
.trail.bright { stroke: rgba(255, 253, 240, 0.75); stroke-width: 2; }
|
|
.head {
|
|
fill: #fffdf0;
|
|
animation: head-life 0.6s ease-out forwards;
|
|
}
|
|
/* Draw from source to head, then the tail chases it into the destination. */
|
|
@keyframes draw-collapse {
|
|
0% { stroke-dashoffset: 100; opacity: 0.95; }
|
|
56% { stroke-dashoffset: 0; opacity: 0.95; }
|
|
100% { stroke-dashoffset: -100; opacity: 0; }
|
|
}
|
|
@keyframes head-life {
|
|
0% { opacity: 0; }
|
|
12% { opacity: 1; }
|
|
60% { opacity: 1; }
|
|
100% { opacity: 0; }
|
|
}
|
|
</style>
|