diff --git a/packages/web/src/fx-sprites/Claw.svelte b/packages/web/src/fx-sprites/Claw.svelte
index ce6c0ba..d584998 100644
--- a/packages/web/src/fx-sprites/Claw.svelte
+++ b/packages/web/src/fx-sprites/Claw.svelte
@@ -5,6 +5,11 @@
let { fx }: { fx: FxOf<"claw"> } = $props();
const uid = $props.id();
const c = $derived(center(fx.at));
+ const GASHES = [
+ { x: -12, cls: "g0" },
+ { x: -3, cls: "g1" },
+ { x: 6, cls: "g2" },
+ ];
@@ -16,18 +21,50 @@
-
-
-
-
+ {#each GASHES as g (g.cls)}
+
+
+
+
+ {/each}
diff --git a/packages/web/src/fx-sprites/DustPuff.svelte b/packages/web/src/fx-sprites/DustPuff.svelte
index 0c5a1fc..2bd1edf 100644
--- a/packages/web/src/fx-sprites/DustPuff.svelte
+++ b/packages/web/src/fx-sprites/DustPuff.svelte
@@ -12,39 +12,52 @@
if (fx.side === "W") return { x: fx.cell.x * CELL, y: mid.y };
return { x: (fx.cell.x + 1) * CELL, y: mid.y };
});
+ /** Edge dust blows perpendicular to the wall; loose dust just rises. */
+ const away = $derived.by(() => {
+ if (fx.kind !== "edge-dust") return { x: 0, y: -12 };
+ return fx.side === "N" || fx.side === "S" ? { x: 11, y: -4 } : { x: 4, y: -11 };
+ });
+
+
+
+
+
+
+
+
+
+
+
-
+
+
-
-
-
-
-
-
-
-
-
diff --git a/packages/web/src/fx-sprites/Hit.svelte b/packages/web/src/fx-sprites/Hit.svelte
index a21b656..af14e1e 100644
--- a/packages/web/src/fx-sprites/Hit.svelte
+++ b/packages/web/src/fx-sprites/Hit.svelte
@@ -3,21 +3,63 @@
import { center } from "./geom";
let { fx }: { fx: FxOf<"hit"> } = $props();
const c = $derived(center(fx.at));
+ const DEBRIS = [40, 165, 285];
-
+
+
+
+
+{#each DEBRIS as deg, i (deg)}
+
+{/each}
diff --git a/packages/web/src/fx-sprites/Portal.svelte b/packages/web/src/fx-sprites/Portal.svelte
index 465bf7a..f9f92ca 100644
--- a/packages/web/src/fx-sprites/Portal.svelte
+++ b/packages/web/src/fx-sprites/Portal.svelte
@@ -9,46 +9,62 @@
{@const y1 = fx.side === "S" ? (fx.cell.y + 1) * CELL : fx.cell.y * CELL}
{@const x2 = fx.side === "W" ? fx.cell.x * CELL : (fx.cell.x + 1) * CELL}
{@const y2 = fx.side === "N" ? fx.cell.y * CELL : (fx.cell.y + 1) * CELL}
-
-
+
+
{:else}
+ width={CELL - 6} height={CELL - 6} rx="6" class="veil outer"
+ style={`transform-origin: ${fx.at.x * CELL + CELL / 2}px ${fx.at.y * CELL + CELL / 2}px`} />
+
{/if}
diff --git a/packages/web/src/fx-sprites/SectorGrind.svelte b/packages/web/src/fx-sprites/SectorGrind.svelte
index 296f624..3b01b78 100644
--- a/packages/web/src/fx-sprites/SectorGrind.svelte
+++ b/packages/web/src/fx-sprites/SectorGrind.svelte
@@ -2,48 +2,130 @@
import type { FxOf } from "../fx";
import { CELL, SECTOR } from "./geom";
let { fx }: { fx: FxOf<"sector-spin" | "sector-slide"> } = $props();
+
+ const S = SECTOR * CELL;
+ const origin = $derived(fx.kind === "sector-spin" ? fx.origin : fx.from);
+ const ox = $derived(origin.x * CELL);
+ const oy = $derived(origin.y * CELL);
+ const cx = $derived(ox + S / 2);
+ const cy = $derived(oy + S / 2);
+ /** Slide direction, unit-ish, for the chevron train. */
+ const dir = $derived.by(() => {
+ if (fx.kind !== "sector-slide") return { x: 0, y: 0 };
+ const dx = fx.to.x - fx.from.x, dy = fx.to.y - fx.from.y;
+ const m = Math.max(1, Math.hypot(dx, dy));
+ return { x: dx / m, y: dy / m };
+ });
+ const CORNERS = $derived([
+ { x: ox + 6, y: oy + 6 }, { x: ox + S - 6, y: oy + 6 },
+ { x: ox + 6, y: oy + S - 6 }, { x: ox + S - 6, y: oy + S - 6 },
+ ]);
{#if fx.kind === "sector-spin"}
- {@const ox = fx.origin.x * CELL}
- {@const oy = fx.origin.y * CELL}
-
+
+
+
+ {#each [45, 135, 225, 315] as deg (deg)}
+
+ {/each}
+
{:else}
- {@const fxp = fx.from.x * CELL}
- {@const fyp = fx.from.y * CELL}
-
+
+
+
+ {#each [0.3, 0.5, 0.7] as t, i (t)}
+
+ {/each}
+
{/if}
+
+ {#each CORNERS as p, i (i)}
+
+ {/each}
+
diff --git a/packages/web/src/fx-sprites/SlimeStuck.svelte b/packages/web/src/fx-sprites/SlimeStuck.svelte
index 24a78f5..429d7b1 100644
--- a/packages/web/src/fx-sprites/SlimeStuck.svelte
+++ b/packages/web/src/fx-sprites/SlimeStuck.svelte
@@ -1,7 +1,6 @@
-
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/Streak.svelte b/packages/web/src/fx-sprites/Streak.svelte
index 4291726..311cc86 100644
--- a/packages/web/src/fx-sprites/Streak.svelte
+++ b/packages/web/src/fx-sprites/Streak.svelte
@@ -3,42 +3,41 @@
import { center } from "./geom";
let { fx }: { fx: FxOf<"streak"> } = $props();
- const uid = $props.id();
const a = $derived(center(fx.from));
const b = $derived(center(fx.to));
+ const d = $derived(`M ${a.x} ${a.y} L ${b.x} ${b.y}`);
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/TacksOw.svelte b/packages/web/src/fx-sprites/TacksOw.svelte
index a75fc8d..75a4473 100644
--- a/packages/web/src/fx-sprites/TacksOw.svelte
+++ b/packages/web/src/fx-sprites/TacksOw.svelte
@@ -3,26 +3,41 @@
import { center } from "./geom";
let { fx }: { fx: FxOf<"tacks-ow"> } = $props();
const c = $derived(center(fx.at));
+ // Each tack: head disc + spike, at its own angle and beat.
+ const TACKS = [
+ { x: -10, y: -4, rot: -18, cls: "" },
+ { x: 5, y: -9, rot: 12, cls: "late" },
+ { x: -1, y: 5, rot: -5, cls: "later" },
+ ];
-
- ✱
- ✱
- ✱
-
+{#each TACKS as t (t.cls)}
+
+
+
+
+
+
+{/each}
diff --git a/packages/web/src/fx-sprites/ThornSnap.svelte b/packages/web/src/fx-sprites/ThornSnap.svelte
index 939202f..4451ad2 100644
--- a/packages/web/src/fx-sprites/ThornSnap.svelte
+++ b/packages/web/src/fx-sprites/ThornSnap.svelte
@@ -1,32 +1,56 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+