@zylem/shaders
v0.8.10
Published
WebGPU-compatible TSL shaders and postprocessing effects for the Zylem game framework.
Readme
@zylem/shaders
WebGPU-compatible TSL shaders and postprocessing effects for the Zylem game framework.
Every shader is a ZylemTSLShader ({ colorNode, positionNode?, transparent? }) — structurally identical to the type in @zylem/game-lib/graphics — so it can be passed directly to game-lib:
import { createWaterSurface, createMagicalLandscape } from '@zylem/shaders';
// As an entity material
const water = createWaterSurface({ waveSpeed: 0.8 });
// ... material: { shader: water }
// As a stage background
const landscape = createMagicalLandscape({ speed: 3 });
// ... createStage({ backgroundShader: landscape }, camera)
// Runtime tweaks via uniforms
water.uniforms.waveStrength.value = 2.0;
landscape.uniforms.color1.value.set('#ff8800');Shaders
| Factory | Use | Source / inspiration |
| --- | --- | --- |
| createMagicalLandscape(options) | Fullscreen background | Magical Landscape by Sabo Sugi |
| createStarryNight(options) | Skybox background | Procedural: star layers, Milky Way band, nebula tint |
| createAlienSky(options) | Skybox background | Zylem examples arena Mars skybox (stars, galaxy, moon, mountains) |
| createPlanetSurface(options) | Mesh surface (UV sphere) | Zylem examples planet demo |
| createPlanetRing(options) | Transparent disk/annulus | Zylem examples planet demo |
| createEnergyShield(options) | Transparent shell (sphere) | Halo-style shield (fresnel rim, hex cells, recharge wave, impact flare/ripple); grew out of the 3d-asteroids ship shield |
| createDissolve(options) | Mesh surface (any) | r3f dissolve-effect sandbox (CSM + gl-noise) |
| createFoliage(options) | Collapsed-quad leaf cluster | Stylized bush sandbox — pair with createFoliageClusterGeometry |
| createHolographic(options) | Transparent mesh surface | ektogamat/threejs-vanilla-holographic-material by Anderson Mancini, plus an optional vertex/color glitch (glitchIntensity) |
| createArcadeDissolve(options) | Subdivided mesh surface | Robotron 2084 enemy-destruction effect (X/Y band shredding, arcade color flash) |
| createWaterSurface(options) | Mesh surface (XZ water plane) | jeantimex/threejs-water surface shaders |
| createLava(options) | Mesh surface (UV-mapped) | three.js webgl_shader_lava by TheGameMaker |
| createShadertoyWaterNoise(options) | Mesh surface | Shadertoy Mt2SzR |
| createShadertoyFire(options) | Mesh surface (transparent) | Shadertoy 3tcBzH |
| createStageTransition(options) | Stage transition (game.nextStage({ transition })) | three.js webgpu_postprocessing_transition |
All factories accept an options object and return the shader with a uniforms bag for runtime tweaking.
createStageTransition returns a ZylemTransitionShader (not a ZylemTSLShader): pass it as game.nextStage({ transition: { shader: createStageTransition({ pattern: 'noise' }) } }). Patterns: fade, wipe, radial, noise, cells; pass a grayscale texture mix map to drive the wipe instead (dark texels transition first).
createWaterSurface also returns a positionNode that displaces vertices by the wave heightfield, so apply it to a subdivided plane (e.g. createPlane({ subdivisions: 160, ... })). Set waveAmplitude: 0 for a flat, normal-mapped-only surface, and pass envMap (a cube texture) to reflect an environment instead of the built-in horizon/zenith sky gradient.
Ability effects
Eight TSL effects adapted from AbilityCastingThreeJS:
createAbilitySigil, createAbilityPortal, createAbilityBeam,
createAbilityLightning, createAbilityFlame, createAbilityBurst,
createAbilityAura, and createAbilityCrystal.
These simplified effects use bounded noise detail and optionally share a small
lookup from createAbilityNoiseTexture(). See usage, source mapping and
performance tradeoffs and the Ability Effects
showcase section. Speedups require device measurements; these interpretations
intentionally reduce visual complexity. MIT attribution ships in
THIRD_PARTY_NOTICES.md.
Retro game effects
All 100 effects from the 100-effect catalog have components with controls in the Retro Game Effects showcase section: palette cycling, ghost transparency, Power Bomb expansion, battle backdrop, painting ripples, matcap metal, Fuzzy screen warp, night vision, iris wipe, lantern cone, water ripple, blob shadow, rainbow road, hit spark, thermal vision and chaff interference. The third batch adds 25 more: weather and mist layers, charge and spell visuals, character materials, reveal effects, a battle-entry swirl, and corridor/track deformation. The completion batch adds the remaining 59, including bounded particle systems, afterimages, sword trails, map projection, camouflage, spells, transformations and scene transitions.
See first-batch usage and
second-batch usage, plus
third-batch factories and
completion usage, costs and limitations.
Materials and transitions import from @zylem/shaders; screen effects import from
@zylem/shaders/postprocessing. These are original visual interpretations;
GPU speedups and original-game fidelity have not been measured.
Shadertoy transpiler
Turn raw Shadertoy GLSL into a consumable shader at runtime (wraps the three.js addons Transpiler + ShaderToyDecoder + TSLEncoder):
import { parseShadertoy } from '@zylem/shaders';
const shader = parseShadertoy(`
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord.xy / iResolution.xy;
fragColor = vec4(uv, 0.5 + 0.5 * sin(iTime), 1.0);
}
`);Supported inputs: iTime, iResolution, fragCoord. Channels, mouse, and multipass buffers are not supported.
Postprocessing
import { createAfterimageEffect } from '@zylem/shaders/postprocessing';
const trails = createAfterimageEffect({ damp: 0.9 });
// stage config: postProcessingEffects: [trails.effect]
trails.uniforms.damp.value = 0.97;| Factory | Effect | Source / inspiration |
| --- | --- | --- |
| createAfterimageEffect(options) | Motion trails | three.js AfterImageNode (TSL port of AfterimageShader.js) |
| createVhsGrainEffect(options) | VHS tape: grain, tracking band, color fringe, scanlines | Composed from three.js CRT helpers + FilmNode-style grain |
| createPixelationEffect(options) | Pixel-art with normal/depth edge outlines | three.js webgpu_postprocessing_pixel by Kody King |
| createRetroEffect(options) | PS1/CRT: vertex snapping, affine textures, dither, curvature | three.js webgpu_postprocessing_retro |
Effects implement ZylemPostEffect — (inputNode, { scenePass, scene, camera }) => outputNode — and plug into game-lib's render pipeline via the stage postProcessingEffects option or rendererManager.setPostProcessingEffects().
createPixelationEffect and createRetroEffect are pass-replacing effects: they render their own scene pass (for extra channels or altered rasterization) rather than transforming the incoming node, so place them first in the postProcessingEffects array.
Install
pnpm add @zylem/shaders threethree is a peer dependency: the library and @zylem/game-lib must share a single Three.js copy, because TSL nodes are not interchangeable across copies.
Repository
This repo is the library itself — src/ builds to the published dist/ — plus a
nested showcase/ Solid/Vite app that exercises every shader on top
of @zylem/game-lib. The showcase resolves @zylem/shaders to source, so shader
edits hot-reload without rebuilding.
Requires Node >= 22.12.0, pnpm >= 10.32.1, and a WebGPU-capable browser for the showcase.
pnpm install
pnpm build # bundle the library to dist/
pnpm dev # rebuild the library on change
pnpm typecheck
pnpm test:shaders # generate retro WGSL; run pnpm build first
pnpm lint
pnpm showcase:dev # showcase on http://localhost:3332
pnpm showcase:buildThe showcase uses Vite's module-runner config loader to transform the
TypeScript plugin exported by @zylem/ui/vite on Node 22.12.
The showcase deploys as a Render static site (see render.yaml);
the library publishes to npm from .github/workflows/publish.yml on a v* tag.
