#63: a shader Property node named "width" quietly took over the sprite
row of the same name. isSpriteProp lives in PropertySchema now and is
derived from FULL_SCHEMAS.sprite instead of being a second list that
drifts. isValidPropertyName rejects those ten names, and the compiler
reports it at the node as its own problem: "width" is a sprite
property, told apart from "not a word" and from a duplicate.
#64: Divide emitted (a / b) and handed NaN to the driver. It emits
divide(a, b) now, with the guard in the prologue next to straight(),
scalar and per channel: zero divided by zero is zero. That was already
the house rule in the behavior and particle graphs - only the shader
had never been told. Clamp comes along as a shader node for the same
reason: the behavior catalog has had it all along.
The default of the Edge param and the address mode the shared sheet physically
carries were the same constant; changing the value would have turned every
sentinel with it and given each shader sprite a full copy of its texture.
SHEET_EDGE ('mirror', what TextureLibrary uploads) is now separate from
DEFAULT_EDGE ('clamp'). A graph whose Sample reads nothing but its own pixel
draws with the plain sheet whatever the Edge says, so the common shader costs
no second copy.
Without a shader the quad's coordinates never leave 0..1, and mirror-repeat
reads like clamp within a texel - so clamp is what a sprite shows anyway.
shaderFingerprint(graph) covers node id/type/params/ports and edge endpoints only;
x/y, collapsed, folded and edge ids stay out. ShaderLibrary keys on it and counts
compiles (__gm.shaderCompiles()). Measured before: one compile per preview step of a
node drag (12 for a harness drag); after: 0, a param change exactly +1.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Fragment-side coordinate nodes instead of vertex nodes: the quad stays the
quad, a UV read plus a sample at a computed coordinate covers flip, scroll,
wave, pixelate and scanlines. Time is a uniform only when a Time node reaches
the Output; a viewport that drew a Time shader redraws from the ticker so the
Scene tab animates without a running world. Edge (Mirror/Repeat/Clamp) is a
second texture variant in TextureLibrary because WebGL binds no TextureStyle
resource of the shader. The compiler now emits #version 300 es first: Pixi
only compiles as ES 3.00 when the fragment says so, and textureSize needs it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A sprite's picture is now a Mesh (unit quad, sibling of its Graphics node, which keeps
only the hit area); a worn shader replaces Pixi's fragment in that draw, so there is no
intermediate texture and no extra render pass. Measured on the HD 630: 400 shaded
sprites hold 60 fps (was 34), 800 hold 56 (was 20).
Two Pixi facts the code leans on: a mesh's texture is bound only for Pixi's own shader,
so GraphShader.wear hands it over; and MeshPipe caches whether a mesh batches and
re-checks it only in a frame without structure changes, so switching a shader on or
off calls mesh.unload().
The console panel mirrors console.group/groupCollapsed/groupEnd and fills the %s %d
%o %c directives, so Pixi's deprecation warning shows its head, not only its stack.
E2E 12 guards against the addChild-on-Graphics warning, 28 counts shaders instead of
filters.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Output gains a number input `alpha`; unconnected it reads the texel's
alpha, like `color` reads the texel. The epilogue premultiplies with the
resolved alpha. New `Texture alpha` node exposes texel.a for maths.
PortDef.inline=false keeps the alpha port without an inline field: every
number port is inline by default, and a typed default of 0 would have made
every shaded sprite invisible. The compiler's texel fallback is typed:
colour ports get rgb, number ports get texel.a.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A shader is an asset carrying a node graph (Texture color, Output, Property,
Color, Add/Subtract/Multiply/Divide, Mix, Luminance) that compiles to the GLSL
fragment of a Pixi filter. The Shader tab reuses the Behavior canvas; a sprite
wears a shader through its Shader picker, and the rows below it are the
graph's Property nodes. Property schema, resolution and deviation take the
project because a sprite's rows now live in another asset. The built-in
registry of the prototype is gone; "Adjust colors" ships as a graph in the
fixture and the three example games.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>