/** Faction tint in the shader instead of on canvas. * * The stock node-image fragment shader lets opaque avatar pixels fully cover * the node color (`mix(v_color, texel, texel.a)`). Scaling that blend factor * down makes every avatar pixel a TINT_ALPHA mix with the node (faction) * color — the same 50% wash we previously baked into per-node canvases, but * with one atlas image per avatar instead of one per avatar×color×theme, and * free re-tinting on theme switches (the color rides the node attribute). * * NOTE: this module touches WebGL at import time via @sigma/node-image, so * it must only ever be imported dynamically (see GraphView). */ import { createNodeImageProgram } from "@sigma/node-image"; const TINT_ALPHA = 0.5; // opacity of the faction color over the avatar const ORIGINAL_MIX = "mix(v_color, texel, texel.a)"; const TINTED_MIX = `mix(v_color, texel, texel.a * ${(1 - TINT_ALPHA).toFixed(3)})`; type ImageProgramOptions = NonNullable[0]>; export function createTintedNodeImageProgram( options: ImageProgramOptions, ): ReturnType { const Base = createNodeImageProgram(options) as any; return class TintedNodeImageProgram extends Base { getDefinition() { const def = super.getDefinition(); const src = def.FRAGMENT_SHADER_SOURCE.replace(ORIGINAL_MIX, TINTED_MIX); if (src === def.FRAGMENT_SHADER_SOURCE) console.warn("fray: @sigma/node-image shader changed shape; avatars will render untinted"); return { ...def, FRAGMENT_SHADER_SOURCE: src }; } } as unknown as ReturnType; }