diff --git a/packages/web/src/App.svelte b/packages/web/src/App.svelte
index 9f177d1..bf09be3 100644
--- a/packages/web/src/App.svelte
+++ b/packages/web/src/App.svelte
@@ -6,6 +6,7 @@
import Card from "./Card.svelte";
import Help from "./Help.svelte";
import Replay from "./Replay.svelte";
+ import FxGallery from "./FxGallery.svelte";
import { fxForEvents, fxTtl, type BoardFx } from "./fx";
import { local } from "./local.svelte";
import { allCardDefs, cardDef, isNumberCard, SIDES, stepTarget, cellKey, isMovableObject, sightedCellsFor, type GameView, eligibleCellsFor } from "@wizwar/engine";
@@ -886,6 +887,9 @@
}
+{#if new URLSearchParams(location.search).has("fx")}
+
+{:else}
{/if}
+{/if}
diff --git a/packages/web/src/fx-sprites/Absorb.svelte b/packages/web/src/fx-sprites/Absorb.svelte
new file mode 100644
index 0000000..99947fe
--- /dev/null
+++ b/packages/web/src/fx-sprites/Absorb.svelte
@@ -0,0 +1,22 @@
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/Bolt.svelte b/packages/web/src/fx-sprites/Bolt.svelte
new file mode 100644
index 0000000..fb29b0a
--- /dev/null
+++ b/packages/web/src/fx-sprites/Bolt.svelte
@@ -0,0 +1,34 @@
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/Burst.svelte b/packages/web/src/fx-sprites/Burst.svelte
new file mode 100644
index 0000000..48296b2
--- /dev/null
+++ b/packages/web/src/fx-sprites/Burst.svelte
@@ -0,0 +1,26 @@
+
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/ChaosSwirl.svelte b/packages/web/src/fx-sprites/ChaosSwirl.svelte
new file mode 100644
index 0000000..4a81a06
--- /dev/null
+++ b/packages/web/src/fx-sprites/ChaosSwirl.svelte
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/Claw.svelte b/packages/web/src/fx-sprites/Claw.svelte
new file mode 100644
index 0000000..3f86da1
--- /dev/null
+++ b/packages/web/src/fx-sprites/Claw.svelte
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/DustPuff.svelte b/packages/web/src/fx-sprites/DustPuff.svelte
new file mode 100644
index 0000000..7e342f8
--- /dev/null
+++ b/packages/web/src/fx-sprites/DustPuff.svelte
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/Fireball.svelte b/packages/web/src/fx-sprites/Fireball.svelte
new file mode 100644
index 0000000..f4bd0c8
--- /dev/null
+++ b/packages/web/src/fx-sprites/Fireball.svelte
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/Fireworks.svelte b/packages/web/src/fx-sprites/Fireworks.svelte
new file mode 100644
index 0000000..f2c3293
--- /dev/null
+++ b/packages/web/src/fx-sprites/Fireworks.svelte
@@ -0,0 +1,26 @@
+
+
+
+ {#each [0, 45, 90, 135, 180, 225, 270, 315] as deg (deg)}
+
+ {/each}
+
+
+
diff --git a/packages/web/src/fx-sprites/Hit.svelte b/packages/web/src/fx-sprites/Hit.svelte
new file mode 100644
index 0000000..a21b656
--- /dev/null
+++ b/packages/web/src/fx-sprites/Hit.svelte
@@ -0,0 +1,23 @@
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/OozeSlip.svelte b/packages/web/src/fx-sprites/OozeSlip.svelte
new file mode 100644
index 0000000..bd13bd0
--- /dev/null
+++ b/packages/web/src/fx-sprites/OozeSlip.svelte
@@ -0,0 +1,23 @@
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/PitFall.svelte b/packages/web/src/fx-sprites/PitFall.svelte
new file mode 100644
index 0000000..9499731
--- /dev/null
+++ b/packages/web/src/fx-sprites/PitFall.svelte
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/Portal.svelte b/packages/web/src/fx-sprites/Portal.svelte
new file mode 100644
index 0000000..465bf7a
--- /dev/null
+++ b/packages/web/src/fx-sprites/Portal.svelte
@@ -0,0 +1,54 @@
+
+
+{#if fx.kind === "portal"}
+ {@const x1 = fx.side === "E" ? (fx.cell.x + 1) * CELL : fx.cell.x * CELL}
+ {@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}
+
+{/if}
+
+
diff --git a/packages/web/src/fx-sprites/Pow.svelte b/packages/web/src/fx-sprites/Pow.svelte
new file mode 100644
index 0000000..bb23aef
--- /dev/null
+++ b/packages/web/src/fx-sprites/Pow.svelte
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/SectorGrind.svelte b/packages/web/src/fx-sprites/SectorGrind.svelte
new file mode 100644
index 0000000..296f624
--- /dev/null
+++ b/packages/web/src/fx-sprites/SectorGrind.svelte
@@ -0,0 +1,49 @@
+
+
+{#if fx.kind === "sector-spin"}
+ {@const ox = fx.origin.x * CELL}
+ {@const oy = fx.origin.y * CELL}
+
+{:else}
+ {@const fxp = fx.from.x * CELL}
+ {@const fyp = fx.from.y * CELL}
+
+{/if}
+
+
diff --git a/packages/web/src/fx-sprites/Shield.svelte b/packages/web/src/fx-sprites/Shield.svelte
new file mode 100644
index 0000000..d89aa69
--- /dev/null
+++ b/packages/web/src/fx-sprites/Shield.svelte
@@ -0,0 +1,26 @@
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/Shimmer.svelte b/packages/web/src/fx-sprites/Shimmer.svelte
new file mode 100644
index 0000000..82c1a3d
--- /dev/null
+++ b/packages/web/src/fx-sprites/Shimmer.svelte
@@ -0,0 +1,25 @@
+
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/SlimeStuck.svelte b/packages/web/src/fx-sprites/SlimeStuck.svelte
new file mode 100644
index 0000000..4634843
--- /dev/null
+++ b/packages/web/src/fx-sprites/SlimeStuck.svelte
@@ -0,0 +1,23 @@
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/Soul.svelte b/packages/web/src/fx-sprites/Soul.svelte
new file mode 100644
index 0000000..1cb2edf
--- /dev/null
+++ b/packages/web/src/fx-sprites/Soul.svelte
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/Sparkle.svelte b/packages/web/src/fx-sprites/Sparkle.svelte
new file mode 100644
index 0000000..174feef
--- /dev/null
+++ b/packages/web/src/fx-sprites/Sparkle.svelte
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/Splash.svelte b/packages/web/src/fx-sprites/Splash.svelte
new file mode 100644
index 0000000..c869694
--- /dev/null
+++ b/packages/web/src/fx-sprites/Splash.svelte
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/Streak.svelte b/packages/web/src/fx-sprites/Streak.svelte
new file mode 100644
index 0000000..554bae3
--- /dev/null
+++ b/packages/web/src/fx-sprites/Streak.svelte
@@ -0,0 +1,23 @@
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/TacksOw.svelte b/packages/web/src/fx-sprites/TacksOw.svelte
new file mode 100644
index 0000000..a75fc8d
--- /dev/null
+++ b/packages/web/src/fx-sprites/TacksOw.svelte
@@ -0,0 +1,28 @@
+
+
+
+ ✱
+ ✱
+ ✱
+
+
+
diff --git a/packages/web/src/fx-sprites/ThornSnap.svelte b/packages/web/src/fx-sprites/ThornSnap.svelte
new file mode 100644
index 0000000..beee6fa
--- /dev/null
+++ b/packages/web/src/fx-sprites/ThornSnap.svelte
@@ -0,0 +1,26 @@
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/Waterbolt.svelte b/packages/web/src/fx-sprites/Waterbolt.svelte
new file mode 100644
index 0000000..a9f7322
--- /dev/null
+++ b/packages/web/src/fx-sprites/Waterbolt.svelte
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/Whiff.svelte b/packages/web/src/fx-sprites/Whiff.svelte
new file mode 100644
index 0000000..f9f3080
--- /dev/null
+++ b/packages/web/src/fx-sprites/Whiff.svelte
@@ -0,0 +1,21 @@
+
+
+
+
+
diff --git a/packages/web/src/fx-sprites/geom.ts b/packages/web/src/fx-sprites/geom.ts
new file mode 100644
index 0000000..fb600d9
--- /dev/null
+++ b/packages/web/src/fx-sprites/geom.ts
@@ -0,0 +1,7 @@
+// Shared geometry for effect sprites. CELL must match Board.svelte's grid.
+export const CELL = 48;
+export const SECTOR = 5;
+export const center = (c: { x: number; y: number }) => ({
+ x: c.x * CELL + CELL / 2,
+ y: c.y * CELL + CELL / 2,
+});
diff --git a/packages/web/src/fx-sprites/index.ts b/packages/web/src/fx-sprites/index.ts
new file mode 100644
index 0000000..0d2b256
--- /dev/null
+++ b/packages/web/src/fx-sprites/index.ts
@@ -0,0 +1,61 @@
+// One sprite component per effect. To change an effect's look, edit its
+// file; to add one, create the component, extend BoardFx in ../fx.ts, and
+// register it here.
+import type { Component } from "svelte";
+import type { BoardFx } from "../fx";
+import Absorb from "./Absorb.svelte";
+import Bolt from "./Bolt.svelte";
+import Burst from "./Burst.svelte";
+import ChaosSwirl from "./ChaosSwirl.svelte";
+import Claw from "./Claw.svelte";
+import DustPuff from "./DustPuff.svelte";
+import Fireball from "./Fireball.svelte";
+import Fireworks from "./Fireworks.svelte";
+import Hit from "./Hit.svelte";
+import OozeSlip from "./OozeSlip.svelte";
+import PitFall from "./PitFall.svelte";
+import Portal from "./Portal.svelte";
+import Pow from "./Pow.svelte";
+import SectorGrind from "./SectorGrind.svelte";
+import Shield from "./Shield.svelte";
+import Shimmer from "./Shimmer.svelte";
+import SlimeStuck from "./SlimeStuck.svelte";
+import Soul from "./Soul.svelte";
+import Sparkle from "./Sparkle.svelte";
+import Splash from "./Splash.svelte";
+import Streak from "./Streak.svelte";
+import TacksOw from "./TacksOw.svelte";
+import ThornSnap from "./ThornSnap.svelte";
+import Waterbolt from "./Waterbolt.svelte";
+import Whiff from "./Whiff.svelte";
+
+export const FX_SPRITES: Record> = {
+ fireball: Fireball,
+ waterbolt: Waterbolt,
+ bolt: Bolt,
+ burst: Burst,
+ splash: Splash,
+ shimmer: Shimmer,
+ shield: Shield,
+ sparkle: Sparkle,
+ whiff: Whiff,
+ hit: Hit,
+ pow: Pow,
+ claw: Claw,
+ absorb: Absorb,
+ portal: Portal,
+ "portal-cell": Portal,
+ streak: Streak,
+ soul: Soul,
+ fireworks: Fireworks,
+ "chaos-swirl": ChaosSwirl,
+ "pit-fall": PitFall,
+ "ooze-slip": OozeSlip,
+ "tacks-ow": TacksOw,
+ "thorn-snap": ThornSnap,
+ "slime-stuck": SlimeStuck,
+ "dust-puff": DustPuff,
+ "edge-dust": DustPuff,
+ "sector-spin": SectorGrind,
+ "sector-slide": SectorGrind,
+} as never;
diff --git a/packages/web/src/fx.ts b/packages/web/src/fx.ts
index 8190075..c5da140 100644
--- a/packages/web/src/fx.ts
+++ b/packages/web/src/fx.ts
@@ -17,6 +17,8 @@ type FxShape =
| { kind: "sector-slide"; from: Cell; to: Cell }
| { kind: "edge-dust"; cell: Cell; side: Side };
export type BoardFx = FxShape & { id: number };
+/** The narrow type of one effect kind (for sprite components). */
+export type FxOf = BoardFx & { kind: K };
let nextId = 1;