The terrain moves in: pits open downward, hedges stand waist-high, ooze is jello
The flat token billboards give way to terrain that inhabits the room. Pits, slime, tacks, and the dimensional warp's rings are painted INTO the flagstones — the home-tile decal pass grows into a general per-cell overlay grid, one texture per cell, alpha-blended texel by texel. Thorn and rose hedges fill their square wall to wall at half height, drawn with a near-bias so the wizard standing among the thorns peeks over the top. The killer ooze rises as a full translucent cube of jello, bricks and bodies visible through it; dust billows; and each dimensional warp mouth throws an additive pillar of violet light up from its floor ring. Billboards learn aspect, translucency, glow, and draw-order bias to carry it all. Nine paintable starters ship — four floor decals under textures/, five standing volumes under terrain3d/ (spec updated for the artist, hedges wide, jello solid, warpglow as light) — shown in the token workshop, rehearsable in place with /?fpv&terrain=thornbush@3,7;jello@4,7. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
a8a63cc27b
commit
1e79f2ffb2
@@ -227,6 +227,17 @@ export interface Billboard {
|
||||
/** Lifted off the floor (0 = feet on the ground). */
|
||||
rise: number;
|
||||
label: string;
|
||||
/** Width as a multiple of height (1 = square; 2 = a cell-wide hedge). */
|
||||
aspect?: number;
|
||||
/** Translucency (jello, dust); 1 or absent is opaque. */
|
||||
alpha?: number;
|
||||
/** Drawn additively, as light (warp pillars). */
|
||||
glow?: boolean;
|
||||
/** Pulled this much nearer for draw order: a hedge wins the tie
|
||||
* against the wizard standing in its own square, who then peeks over. */
|
||||
bias?: number;
|
||||
/** Procedural stand-in name while the painted file loads. */
|
||||
fallback?: string;
|
||||
/** A reflection seen through a warp mouth, not the thing itself. */
|
||||
warped?: boolean;
|
||||
}
|
||||
@@ -298,19 +309,42 @@ export function billboards(
|
||||
scale: 0.4, rise: 0, label: "treasure",
|
||||
});
|
||||
}
|
||||
// The floor's furniture: bushes stand tall, hazards squat low. Stone is
|
||||
// a wall to the rays and needs no sprite.
|
||||
const TERRAIN_SCALE: Record<string, number> = {
|
||||
thornbush: 0.7, rosebush: 0.7, safe: 0.55, ooze: 0.35, slime: 0.3,
|
||||
tacks: 0.25, pit: 0.35, dust: 0.6,
|
||||
};
|
||||
// The floor's furniture, standing in the room. Bushes fill the square
|
||||
// to half height (a wizard peeks over); the killer ooze is a whole
|
||||
// translucent cube of jello; dust billows. Pits, slime, tacks, and
|
||||
// dimensional warps are painted INTO the floor by the decal pass, and
|
||||
// stone is a wall to the rays — none of those need a sprite.
|
||||
for (const [k, content] of Object.entries(view.squareContents)) {
|
||||
if (content.kind === "stone") continue;
|
||||
const file = TERRAIN_ART[content.kind];
|
||||
const scale = TERRAIN_SCALE[content.kind];
|
||||
if (!file || !scale) continue;
|
||||
const [tx, ty] = k.split(",").map(Number) as [number, number];
|
||||
out.push({ x: tx + 0.5, y: ty + 0.5, src: art(file, "terrain"), scale, rise: 0, label: content.kind });
|
||||
const at = { x: tx + 0.5, y: ty + 0.5 };
|
||||
if (content.kind === "thornbush" || content.kind === "rosebush") {
|
||||
out.push({
|
||||
...at, src: `/terrain3d/${content.kind}.png`, fallback: content.kind,
|
||||
scale: 0.5, aspect: 2, rise: 0, bias: 0.18, label: content.kind,
|
||||
});
|
||||
} else if (content.kind === "ooze") {
|
||||
out.push({
|
||||
...at, src: "/terrain3d/jello.png", fallback: "jello",
|
||||
scale: 0.96, aspect: 1.04, rise: 0, alpha: 0.6, bias: 0.18, label: "ooze",
|
||||
});
|
||||
} else if (content.kind === "dust") {
|
||||
out.push({
|
||||
...at, src: "/terrain3d/dust.png", fallback: "dust",
|
||||
scale: 0.85, aspect: 1.1, rise: 0, alpha: 0.55, bias: 0.18, label: "dust",
|
||||
});
|
||||
} else if (content.kind === "safe") {
|
||||
out.push({ ...at, src: art(TERRAIN_ART["safe"]!, "terrain"), scale: 0.55, rise: 0, label: "safe" });
|
||||
}
|
||||
}
|
||||
// Dimensional warp mouths throw pillars of light from their floor rings.
|
||||
for (const w of view.dimWarps) {
|
||||
for (const cellAt of [w.a, w.b]) {
|
||||
out.push({
|
||||
x: cellAt.x + 0.5, y: cellAt.y + 0.5,
|
||||
src: "/terrain3d/warpglow.png", fallback: "warpglow",
|
||||
scale: 0.95, aspect: 0.5, rise: 0, alpha: 0.6, glow: true, label: "dimwarp",
|
||||
});
|
||||
}
|
||||
}
|
||||
for (const [k, cards] of Object.entries(view.groundObjects)) {
|
||||
const file = cards[0] ? objectArt(cards[0].cardId) : null;
|
||||
|
||||
Reference in New Issue
Block a user