The maze through a wizard's eyes: the first-person raycaster (/?fpv)

Stage one of the replay vision: a canvas raycaster over the GameView —
walls on edges marched by DDA, doors with lintels, firewalls that
flicker, rim warp mouths that shimmer violet, token art billboarded and
occluded per column, torchlit vignette. It renders the view a player
would be SENT, so an illusion this wizard has not seen through stands as
solid as stone in first person too. The /?fpv workshop free-flies a
dealt maze with wall collision, a minimap eye-cone, and ?seed=&x=&y=&dir=
to stand the camera anywhere. Next: drive it from the replay reel.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-23 12:19:03 -04:00
co-authored by Claude Fable 5
parent a4f572a164
commit 3c479eddbb
5 changed files with 466 additions and 1 deletions
+5 -1
View File
@@ -8,6 +8,7 @@
import Replay from "./Replay.svelte";
import FxGallery from "./FxGallery.svelte";
import TokenGallery from "./TokenGallery.svelte";
import FpvWorkshop from "./fpv/FpvWorkshop.svelte";
import { scheduleFx, type BoardFx } from "./fx";
import { prefs, savePrefs } from "./prefs.svelte";
import { CREATURE_ART, objectArt, TERRAIN_ART, tokenArt } from "./art";
@@ -41,6 +42,7 @@
/** Which pending attack the player has already acknowledged (modal dismissed). */
const fxWorkshop = new URLSearchParams(location.search).has("fx");
const tokenWorkshop = new URLSearchParams(location.search).has("tokens");
const fpvWorkshop = new URLSearchParams(location.search).has("fpv");
let attackNoticeSeen = $state<string | null>(null);
/** The interruption fanfare, dismissed once per window. */
let momentSeen = $state(false);
@@ -1231,7 +1233,9 @@
}
</script>
{#if tokenWorkshop}
{#if fpvWorkshop}
<FpvWorkshop />
{:else if tokenWorkshop}
<TokenGallery />
{:else if fxWorkshop}
<FxGallery />