HD sprites in the pixel world
The "inverse FFT" question — can a crisp hi-res character live convincingly inside the chunky 480×270 voxel world? Two pieces: proving per-pixel depth occlusion works, and measuring why zoomed-in sprites look janky.
Depth-clip probe — per-pixel occlusion by the pixel world
A native-resolution HD sprite (a chroma-keyed skeleton) is occluded per-pixel by the 480 world. The trick: occluders render their linear view-depth into a separate 480×270 SubViewport, and the sprite's canvas shader samples that depth with NEAREST filtering — so the bite edge snaps to the world's pixel grid (chunky, not smooth). That's deliberate: the sprite stays crisp inside, but where it meets the world it's occluded by the world's own pixels, which is what makes the res-contrast read as authored rather than a floating cutout.
It also demonstrates correctness, not just "any geometry hides it": the orange pillar bites the left, the blue block bites the head, the magenta block bites the shins — all simultaneously and per-pixel — while the teal block behind the sprite does NOT bite (the skeleton's ribs draw over it). That's true depth. A first-pass world-light + shadow transfer is wired too (the sprite tints to the scene light; a ground shadow).
Resolution A/B — why zoomed-in sprites go janky
The same portrait, the same breathing scale-sin, three ways at matched on-screen size. 480-smooth (billboard in the world, sub-pixel scale) resamples to mush. 480-snap (scale quantized to the pixel grid) is crisp but the animation steps — it kills a smooth idle. Native-HD (on the overlay layer) is the only path that's crisp and smooth, retaining ~3× the detail.
docs/SPRITE-RESOLUTION-PATHS.md.Energy trails
Plasma · electric · ember — one ribbon, three looks
A projectile/spell trail is a camera-facing ribbon rebuilt every frame from a ring buffer of the head's
recent positions (the same strip technique the effects library uses for its ribbons). The shader scrolls
two-rate noise along the length with a bright transverse centerline; a ridge lever thresholds
it thin for the electric arc. Head→tail fade and taper are carried in the vertex color.
VfxTrail.attach() follows any moving node; sweep() is a one-shot arc.
Cashing in the noise engine
One posterized FBM+domain-warp shader was already driving lava/water/orbs. This wave spends it across five real gameplay systems.
Dissolve / materialize
A sprite is eaten away (or built up) along a noise threshold, leaving a hot HDR burn edge. Directional bias sweeps the burn up for death, down for spawn.
Status auras
A noise billboard per status (burning/poison/frost/shield/rage) that tracks the unit and composes with the existing emote tints. Stacks cleanly.
AoE fields + hazard tiles
Timed circular spell fields (fire nova / poison cloud / frost zone) that pop in, sustain, and fade; plus persistent per-cell tile hazards snapped to the game grid.
Weather
Wires the sky sim's drifting cloud-cover (which shadows the terrain) plus a falling-particle overlay for rain/snow/ash.
The distortion family
Summon black hole · dimensional cut · shockwave — one kernel
The cinematic-tier screen-space posts, refactored onto a single ScreenFX rig (CanvasLayer +
back-buffer copy + full-screen shader). A small diegetic in-world rift opens the reel; then the full-screen
summon black hole (gravitational lensing + chromatic aberration, verified pixel-identical after the
refactor), the dimensional cut (a slash tears the screen apart onto an energy void), and the new
shockwave (an expanding radial impact ring).
Heat-haze over lava — caveat
A diegetic screen-read shimmer rising off a hot surface. Also the best look at the molten lava (Worley crust + glowing cracks + downhill flow on the real fluid sim).
distort_fx is a full-replace
refraction (built for the black hole), so over the very bright, high-contrast molten crust the haze reads as
prominent patches, not a subtle shimmer. Shipped as a valid primitive (subtle over lower-contrast surfaces);
the real fix — a dedicated additive-perturbation haze shader — is logged as a follow-on.Anti-occlusion & the info layer
Wall-fade · x-ray silhouette · gated nameplate
For a unit you command, total occlusion is bad UX — so this is the anti-occlusion doctrine. A camera→unit raycast (against a real collider pillar) drives three responses as the camera orbits: wall-fade (the blocking pillar goes translucent), x-ray silhouette (a cyan ghost shows the unit through the wall), and a gated nameplate (the label fades while the unit is hidden). Note: dither "screen-door" fade was verified unimplemented in this renderer, so wall-fade uses real alpha.
Cellular follow-ons
Water caustics
A drifting Worley cell-web brightens the deeper water body — the classic caustic network. Gated so only the water preset has it; lava and the other fluids are untouched.
Cracked ground · obsidian
A Worley cell lever on the noise engine adds two ground presets: cracked (dark earth
with glowing ember veins) and obsidian (blue-black with cyan veins). The original presets are
unchanged (the lever defaults off).
Your decisions (when you're ready)
- HD sprites — which characters go HD (heroes/bosses vs all units)? Lighting depth (the v1 light-tint
vs per-pixel directional + a silhouette shadow)? Asset pipeline (commission alpha cutouts vs standardize the
chroma-key bake)? Detail in
docs/SPRITE-RESOLUTION-PATHS.md. - iso_main integration — which systems into the real battle first? My ranking: status auras + hazard tiles → dissolve (death/spawn) → readable-text migration → the rest as spell content.
- Tuning — several defaults are dialed for demo legibility (aura size, caustics strength, weather density). Trivial to adjust to taste.
Suggested follow-ons
- iso_main hi-res text migration + wire the occlusion gate
- Additive-perturbation heat-haze shader (the real subtle haze)
- HD-sprite lighting v2 — per-pixel directional + silhouette shadow
- Wire noise systems into gameplay (hazard damage, aura on-apply, field on-cast, dissolve on-death)
- Projectile auto-trail seam (
on_headon the projectile verb) - White-hole / eclipse summon variant (cut from this grind)
- Dedicated status-icon art (replace placeholder glyphs)
- GemField → iso_main adoption (documented seam)
- Flow-map two-phase advection for lava (researched)
out/render cleanup (~90 clips → keep the finals)