Scoped to everything since the last pass (3308850). Three blind
reviews, every finding verified before touching anything.
Confirmed and fixed: two identical comment-splitting insertions left
doc comments orphaned from their fields (net and local alike); a
51-line CSS fossil of the pre-extraction inline effects survived in
Board.svelte; the rev-13 miss-roll test asserted tautologies while
its comment claimed a check the code never made — it now proves the
die was consumed, and the skeleton is no longer returned as trollId;
the sprite registry's `as never` silently disabled the completeness
its annotation advertised (now a mapped type, one cast at the
dispatch seam); a dead ternary guarded a union that doesn't exist;
Bolt carried a duplicate .fork rule from a color iteration; fxTtl
contradicted three sprites' real animation lengths; the permanence
sentinel was reinvented as a magic 9000 (the engine now exports
isPermanentDuration); CELL was declared thrice (fx.ts now imports
it); App and Replay ran two divergent fx schedulers (one scheduleFx
now, cancellable — stale flourishes can no longer fire after leaving
a game); TokenArt retried missing files forever; the anti-anti
escape guards merge with the gate asymmetry explained; wall-of-fire's
rev-12 carve-out is marked; overLimit ignored a displayed BRAINSTONE
(bots over-discarded by two); botRemark's header mis-stated its own
branches; deliverGold fired on any drop, not a home-base delivery;
escape and win banter never fired from the steps that carry them.
Rejected: "as a human would" (house voice); FxGallery's dev-harness
framing (trimmed one plea, kept the facts).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
70 lines
2.0 KiB
Svelte
70 lines
2.0 KiB
Svelte
<script lang="ts">
|
|
import type { FxOf } from "../fx";
|
|
|
|
let { fx }: { fx: FxOf<"bolt"> } = $props();
|
|
const uid = $props.id();
|
|
|
|
/** A fresh jagged path every strike, plus two forks off mid-joints. */
|
|
const geom = $derived.by(() => {
|
|
const a = fx.a, b = fx.b;
|
|
const segs = 6;
|
|
const joints: { x: number; y: number }[] = [a];
|
|
for (let i = 1; i < segs; i++) {
|
|
const t = i / segs;
|
|
joints.push({
|
|
x: a.x + (b.x - a.x) * t + (Math.random() - 0.5) * 16,
|
|
y: a.y + (b.y - a.y) * t + (Math.random() - 0.5) * 16,
|
|
});
|
|
}
|
|
joints.push(b);
|
|
const points = joints.map((p) => `${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(" ");
|
|
const fork = (j: { x: number; y: number }) => {
|
|
const dx = (Math.random() - 0.5) * 26, dy = (Math.random() - 0.5) * 26;
|
|
return `M ${j.x} ${j.y} l ${dx / 2} ${dy / 2} l ${dx / 2 + (Math.random() - 0.5) * 8} ${dy / 2}`;
|
|
};
|
|
return { points, forks: [fork(joints[2]!), fork(joints[4]!)] };
|
|
});
|
|
</script>
|
|
|
|
<defs>
|
|
<filter id={`bolt-glow-${uid}`} x="-60%" y="-60%" width="220%" height="220%">
|
|
<feGaussianBlur stdDeviation="4" result="blur" />
|
|
<feMerge><feMergeNode in="blur" /><feMergeNode in="SourceGraphic" /></feMerge>
|
|
</filter>
|
|
</defs>
|
|
|
|
<g class="bolt" filter={`url(#bolt-glow-${uid})`}>
|
|
<polyline points={geom.points} class="wide" />
|
|
{#each geom.forks as d, i (i)}
|
|
<path {d} class="fork" />
|
|
{/each}
|
|
<polyline points={geom.points} class="core" />
|
|
</g>
|
|
|
|
<style>
|
|
.bolt .wide {
|
|
fill: none;
|
|
stroke: #e6a812;
|
|
stroke-width: 5.5;
|
|
stroke-linejoin: round;
|
|
opacity: 0.75;
|
|
}
|
|
.bolt .fork {
|
|
fill: none;
|
|
stroke: #f5d54a;
|
|
stroke-width: 1.6;
|
|
stroke-linejoin: round;
|
|
}
|
|
.bolt .core {
|
|
fill: none;
|
|
stroke: #fffdf0;
|
|
stroke-width: 2;
|
|
stroke-linejoin: round;
|
|
}
|
|
.bolt { animation: bolt-flicker 0.5s steps(2, jump-none) forwards; }
|
|
@keyframes bolt-flicker {
|
|
0% { opacity: 0; } 15% { opacity: 1; } 40% { opacity: 0.3; }
|
|
60% { opacity: 1; } 100% { opacity: 0; }
|
|
}
|
|
</style>
|