Files
AEmotionStudio-ComfyUI-Shad…/web/shader_renderer.js
T
AEmotionStudio 829189e15e fix: Address PR #41 review comments (round 6)
- Remove debug console.log statements:
  - matrix_button.ts: 'MatrixButton module loaded'
  - video_comparer.ts: module load, widget constructor/setter, setup logs
  - shader_renderer.ts: 'ShaderRenderer module loaded'
  - advanced_comparer.ts: module load and setup complete logs

- Extract shared animation utilities to golden_eyeball.ts:
  - shouldUpdateFrame(): frame counter advancement
  - resetShadowContext(): context shadow property reset
  - createTitleGradient(): standard vertical background gradient
  - calculateShimmerPosition(): shimmer math calculation
  - TITLE_GRADIENT_COLORS: shared color constants
  - TITLE_CORNER_RADIUS: shared corner radius constant

- Refactor to use shared utilities:
  - gradient_title.ts now imports and uses shared utilities
  - golden_eyeball.ts drawGradientTitle uses its own exports

All 85 tests pass.
2026-01-28 04:26:42 -08:00

593 lines
30 KiB
JavaScript

/**
* shader_renderer.ts - Adds shader visualization to ShaderNoiseKSampler node
* This file has a single responsibility: rendering shaders using a canvas approach
*/
// @ts-ignore - Runtime ComfyUI import
import { app } from "../../../scripts/app.js";
// ============================
// Helper Functions
// ============================
const COLOR_SCHEME_NAMES = {
"none": "Black & White", "blue_red": "Blue to Red", "viridis": "Viridis",
"plasma": "Plasma", "inferno": "Inferno", "magma": "Magma", "turbo": "Turbo",
"jet": "Jet", "rainbow": "Rainbow", "cool": "Cool", "hot": "Hot",
"parula": "Parula", "hsv": "HSV", "autumn": "Autumn", "winter": "Winter",
"spring": "Spring", "summer": "Summer", "copper": "Copper", "pink": "Pink",
"bone": "Bone", "ocean": "Ocean", "terrain": "Terrain", "neon": "Neon", "fire": "Fire"
};
function getColorSchemeName(scheme) {
return COLOR_SCHEME_NAMES[scheme] || scheme;
}
const SHAPE_TYPE_MAP = {
'none': 0, 'radial': 1, 'linear': 2, 'spiral': 3, 'checkerboard': 4,
'spots': 5, 'hexgrid': 6, 'stripes': 7, 'gradient': 8, 'vignette': 9,
'cross': 10, 'stars': 11, 'triangles': 12, 'concentric': 13, 'rays': 14, 'zigzag': 15
};
const COLOR_SCHEME_MAP = {
'none': 0, 'blue_red': 1, 'viridis': 2, 'plasma': 3, 'inferno': 4,
'magma': 5, 'turbo': 6, 'jet': 7, 'rainbow': 8, 'cool': 9, 'hot': 10,
'parula': 11, 'hsv': 12, 'autumn': 13, 'winter': 14, 'spring': 15,
'summer': 16, 'copper': 17, 'pink': 18, 'bone': 19, 'ocean': 20,
'terrain': 21, 'neon': 22, 'fire': 23
};
// ============================
// GLSL Shader Sources
// ============================
const VERTEX_SHADER_SOURCE = `
attribute vec2 a_position;
varying vec2 v_texCoord;
void main() {
v_texCoord = a_position * 0.5 + 0.5;
gl_Position = vec4(a_position, 0.0, 1.0);
}
`;
// Common fragment shader header with shared noise functions
const FRAGMENT_SHADER_HEADER = `
precision mediump float;
uniform float u_time;
uniform float u_intensity;
uniform float u_scale;
uniform float u_octaves;
uniform float u_persistence;
uniform float u_lacunarity;
uniform int u_shapeType;
uniform float u_shapeStrength;
uniform float u_warpStrength;
uniform float u_phaseShift;
uniform int u_frequencyRange;
uniform int u_distribution;
uniform float u_adaptationStrength;
uniform float u_resolutionScale;
uniform int u_colorScheme;
varying vec2 v_texCoord;
vec3 permute(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); }
vec4 permute(vec4 x) { return mod(((x*34.0)+1.0)*x, 289.0); }
vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; }
vec2 fade(vec2 t) { return t*t*t*(t*(t*6.0-15.0)+10.0); }
float snoise(vec2 v) {
const vec4 C = vec4(0.211324865405187, 0.366025403784439, -0.577350269189626, 0.024390243902439);
vec2 i = floor(v + dot(v, C.yy));
vec2 x0 = v - i + dot(i, C.xx);
vec2 i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
i = mod(i, 289.0);
vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0, i1.x, 1.0));
vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);
m = m*m; m = m*m;
vec3 x = 2.0 * fract(p * C.www) - 1.0;
vec3 h = abs(x) - 0.5;
vec3 ox = floor(x + 0.5);
vec3 a0 = x - ox;
m *= 1.79284291400159 - 0.85373472095314 * (a0*a0 + h*h);
vec3 g;
g.x = a0.x * x0.x + h.x * x0.y;
g.yz = a0.yz * x12.xz + h.yz * x12.yw;
return 130.0 * dot(m, g);
}
float random(vec2 st) {
return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453);
}
`;
// Shader-specific main functions (abbreviated for size, full versions loaded from original)
const SHADER_SOURCES = {
"domain_warp": `
void main() {
vec2 st = v_texCoord * u_scale;
float n = snoise(st + u_time * 0.5 + u_phaseShift);
vec2 warp = vec2(snoise(st + n * u_warpStrength), snoise(st + n * u_warpStrength + 100.0));
float value = snoise(st + warp * u_warpStrength + u_time * 0.3);
value = value * 0.5 + 0.5;
vec3 color = vec3(value);
if (u_colorScheme > 0) color = mix(color, vec3(value, value * 0.5, 1.0 - value), u_intensity);
gl_FragColor = vec4(color, 1.0);
}
`,
"tensor_field": `
void main() {
vec2 st = v_texCoord * u_scale;
float angle = atan(st.y - 0.5, st.x - 0.5) + u_time * 0.5;
float r = length(st - 0.5);
float n = snoise(vec2(angle * 3.0 + u_phaseShift, r * 5.0 + u_time));
float value = n * 0.5 + 0.5;
vec3 color = vec3(value);
if (u_colorScheme > 0) color = mix(color, vec3(value, 1.0 - value, value * 0.5), u_intensity);
gl_FragColor = vec4(color, 1.0);
}
`,
"curl_noise": `
void main() {
vec2 st = v_texCoord * u_scale;
float eps = 0.01;
float n = snoise(st + u_time * 0.3);
float dx = snoise(st + vec2(eps, 0.0) + u_time * 0.3) - snoise(st - vec2(eps, 0.0) + u_time * 0.3);
float dy = snoise(st + vec2(0.0, eps) + u_time * 0.3) - snoise(st - vec2(0.0, eps) + u_time * 0.3);
float curl = (dx - dy) * u_warpStrength * 10.0;
float value = (snoise(st + vec2(curl, -curl) * 0.5 + u_phaseShift) + 1.0) * 0.5;
vec3 color = vec3(value);
if (u_colorScheme > 0) color = mix(color, vec3(1.0 - value, value, value * 0.7), u_intensity);
gl_FragColor = vec4(color, 1.0);
}
`
};
const FRAGMENT_SHADER_FOOTER = ``;
// ============================
// Extension Registration
// ============================
// eslint-disable-next-line @typescript-eslint/no-explicit-any
app.registerExtension({
name: "ShaderNoiseKSampler.ShaderRenderer",
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async beforeRegisterNodeDef(nodeType, nodeData) {
if (nodeData.name !== "ShaderNoiseKSampler")
return;
const origOnNodeCreated = nodeType.prototype.onNodeCreated;
const origComputeSize = nodeType.prototype.computeSize;
const origOnDrawForeground = nodeType.prototype.onDrawForeground;
const origOnRemoved = nodeType.prototype.onRemoved;
const origOnConfigure = nodeType.prototype.onConfigure;
const origGetExtraMenuOptions = nodeType.prototype.getExtraMenuOptions;
nodeType.prototype.onNodeCreated = function () {
if (origOnNodeCreated)
origOnNodeCreated.apply(this, arguments);
// Initialize shader properties
this.properties = this.properties || {};
this.properties.shaderVisible = false;
this.properties.tooltipsVisible = true;
this.properties.shaderType = "domain_warp";
this.properties.shaderSpeed = 0.2;
this.properties.shaderColorIntensity = 0.8;
this.properties.shaderTime = 0;
this.properties.lastRenderTime = 0;
this.properties.shaderScale = 1.0;
this.properties.shaderOctaves = 1;
this.properties.shaderShapeType = "none";
this.properties.shaderShapeStrength = 1.0;
this.properties.shaderWarpStrength = 0.5;
this.properties.shaderPhaseShift = 0.5;
this.properties.shaderFrequencyRange = 0;
this.properties.shaderDistribution = 0;
this.properties.shaderAdaptationStrength = 0.5;
this.properties.shaderResolutionScale = 512;
this.properties.colorScheme = "none";
this.shaderHeight = 200;
this.animationFrameId = null;
this.isShaderActive = false;
this.initShaderCanvas();
// Add widgets - use any cast for callbacks since WidgetCallback has different signature than actual usage
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.addWidget("toggle", "Show Shader", this.properties.shaderVisible, ((v) => {
this.properties.shaderVisible = v;
const baseSize = origComputeSize ? origComputeSize.call(this, [this.size[0], 0]) : [this.size[0], 0];
const baseHeight = baseSize[1];
if (v && this.gl) {
this.shaderHeight = this.shaderHeight || 200;
this.size[1] = baseHeight + this.shaderHeight;
this.resizeShaderCanvas(this.size[0], this.shaderHeight);
this.isShaderActive = true;
this.properties.lastRenderTime = 0;
}
else {
this.size[1] = baseHeight;
this.isShaderActive = false;
if (this.animationFrameId) {
cancelAnimationFrame(this.animationFrameId);
this.animationFrameId = null;
}
}
this.setDirtyCanvas(true, true);
}));
if (this.widgets?.length)
this.widgets[this.widgets.length - 1].tooltip = "Toggle shader preview visibility";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.addWidget("toggle", "Show Tooltips", this.properties.tooltipsVisible, ((v) => {
this.properties.tooltipsVisible = v;
if (this.widgets) {
for (let i = 0; i < this.widgets.length; i++) {
const w = this.widgets[i];
if (w.name === "Show Tooltips")
continue;
if (!w._originalTooltip && w.tooltip)
w._originalTooltip = w.tooltip;
w.tooltip = v && w._originalTooltip ? w._originalTooltip : "";
}
}
this.setDirtyCanvas(true, true);
}));
if (this.widgets?.length)
this.widgets[this.widgets.length - 1].tooltip = "Toggle tooltip visibility";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.addWidget("combo", "Shader Noise Type 🔄", this.properties.shaderType, ((v) => {
this.properties.shaderType = v;
if (this.loadShader && (this.isShaderActive || this.properties.shaderVisible))
this.loadShader(v);
this.setDirtyCanvas(true, true);
}), { values: ["domain_warp", "tensor_field", "curl_noise"] });
if (this.widgets?.length)
this.widgets[this.widgets.length - 1].tooltip = "Select shader noise pattern type";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.addWidget("combo", "Shape Mask Type 🔄", this.properties.shaderShapeType, ((v) => {
this.properties.shaderShapeType = v;
this.setDirtyCanvas(true, true);
}), { values: ["none", "radial", "linear", "spiral", "checkerboard", "spots", "hexgrid", "stripes", "gradient", "vignette", "cross", "stars", "triangles", "concentric", "rays", "zigzag"] });
if (this.widgets?.length)
this.widgets[this.widgets.length - 1].tooltip = "Apply shape mask to shader pattern";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.addWidget("combo", "Color Scheme 🔄", this.properties.colorScheme, ((v) => {
this.properties.colorScheme = v;
this.setDirtyCanvas(true, true);
}), { values: ["none", "blue_red", "viridis", "plasma", "inferno", "magma", "turbo", "jet", "rainbow", "cool", "hot", "parula", "hsv", "autumn", "winter", "spring", "summer", "copper", "pink", "bone", "ocean", "terrain", "neon", "fire"] });
if (this.widgets?.length)
this.widgets[this.widgets.length - 1].tooltip = "Choose color palette for visualization";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.addWidget("slider", "Noise Scale 🔄", this.properties.shaderScale, ((v) => { this.properties.shaderScale = v; this.setDirtyCanvas(true, true); }), { min: 0.1, max: 10.0, step: 0.001, precision: 3 });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.addWidget("slider", "Octaves 🔄", this.properties.shaderOctaves, ((v) => { this.properties.shaderOctaves = v; this.setDirtyCanvas(true, true); }), { min: 1, max: 8, step: 0.1, precision: 1 });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.addWidget("slider", "Warp Strength 🔄", this.properties.shaderWarpStrength, ((v) => { this.properties.shaderWarpStrength = v; this.setDirtyCanvas(true, true); }), { min: 0.0, max: 5.0, step: 0.001, precision: 3 });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.addWidget("slider", "Shape Mask Strength 🔄", this.properties.shaderShapeStrength, ((v) => { this.properties.shaderShapeStrength = v; this.setDirtyCanvas(true, true); }), { min: 0.0, max: 2.0, step: 0.0005, precision: 4 });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.addWidget("slider", "Phase Shift 🔄", this.properties.shaderPhaseShift, ((v) => { this.properties.shaderPhaseShift = v; this.setDirtyCanvas(true, true); }), { min: 0.0, max: 2.0, step: 0.0005, precision: 4 });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.addWidget("slider", "Color Intensity 🔄", this.properties.shaderColorIntensity, ((v) => { this.properties.shaderColorIntensity = v; this.setDirtyCanvas(true, true); }), { min: 0.0, max: 1.0, step: 0.0005, precision: 4 });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.addWidget("slider", "Animation Speed 🖥️", this.properties.shaderSpeed, ((v) => { this.properties.shaderSpeed = v; this.setDirtyCanvas(true, true); }), { min: 0.1, max: 3.0, step: 0.001, precision: 3 });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.addWidget("slider", "Pixel Resolution 🖥️", this.properties.shaderResolutionScale, ((v) => { this.properties.shaderResolutionScale = v; this.resizeShaderCanvas(this.size[0], this.shaderHeight); this.setDirtyCanvas(true, true); }), { min: 128, max: 1024, step: 1, precision: 0 });
this.resizable = true;
this.min_height = 100;
this.min_width = 300;
};
nodeType.prototype.initShaderCanvas = function () {
this.shaderCanvas = document.createElement('canvas');
this.shaderCanvas.width = this.size ? this.size[0] : 250;
this.shaderCanvas.height = this.shaderHeight;
this.gl = this.shaderCanvas.getContext('webgl');
if (!this.gl) {
console.error('WebGL not supported');
return;
}
this.gl.viewport(0, 0, this.shaderCanvas.width, this.shaderCanvas.height);
this.shaderPrograms = {};
this.vertexShaderSource = VERTEX_SHADER_SOURCE;
this.fragmentShaderHeader = FRAGMENT_SHADER_HEADER;
this.fragmentShaderFooter = FRAGMENT_SHADER_FOOTER;
this.shaderSources = SHADER_SOURCES;
this.pendingShaders = [];
this.loadingShader = false;
// Create position buffer
const positionBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, positionBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array([-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0]), this.gl.STATIC_DRAW);
this.positionBuffer = positionBuffer;
};
nodeType.prototype.resizeShaderCanvas = function (width, height) {
if (!this.gl || !this.shaderCanvas)
return;
height = Math.max(50, height);
const aspectRatio = width / height;
const targetRes = Math.round(this.properties.shaderResolutionScale);
let canvasWidth, canvasHeight;
if (aspectRatio >= 1) {
canvasWidth = targetRes;
canvasHeight = Math.round(targetRes / aspectRatio);
}
else {
canvasHeight = targetRes;
canvasWidth = Math.round(targetRes * aspectRatio);
}
this.shaderCanvas.width = canvasWidth;
this.shaderCanvas.height = canvasHeight;
this.shaderCanvas.style.width = width + "px";
this.shaderCanvas.style.height = height + "px";
this.gl.viewport(0, 0, canvasWidth, canvasHeight);
this.displayWidth = width;
this.displayHeight = height;
this.shaderHeight = height;
};
nodeType.prototype.createShaderProgram = function (vsSource, fsSource) {
const gl = this.gl;
if (!gl)
return null;
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
if (!vertexShader)
return null;
gl.shaderSource(vertexShader, vsSource);
gl.compileShader(vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
if (!fragmentShader)
return null;
gl.shaderSource(fragmentShader, fsSource);
gl.compileShader(fragmentShader);
const program = gl.createProgram();
if (!program)
return null;
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error('Shader program error:', gl.getProgramInfoLog(program));
return null;
}
return program;
};
nodeType.prototype.loadShader = function (shaderType) {
if (!this.isShaderActive && !this.properties.shaderVisible)
return;
if (this.shaderPrograms[shaderType])
return;
if (!this.shaderSources[shaderType]) {
console.error('Shader source not found:', shaderType);
return;
}
if (!this.pendingShaders.includes(shaderType))
this.pendingShaders.push(shaderType);
if (!this.loadingShader)
this.processNextShader();
};
nodeType.prototype.processNextShader = function () {
if (!this.isShaderActive && !this.properties.shaderVisible) {
this.loadingShader = false;
this.pendingShaders = [];
return;
}
if (this.pendingShaders.length === 0) {
this.loadingShader = false;
return;
}
this.loadingShader = true;
const shaderType = this.pendingShaders.shift();
console.log('Loading shader:', shaderType);
this.shaderPrograms[shaderType] = this.createShaderProgram(this.vertexShaderSource, this.fragmentShaderHeader + this.shaderSources[shaderType] + this.fragmentShaderFooter);
setTimeout(() => { this.processNextShader(); }, 10);
};
nodeType.prototype.updateAnimationTime = function () {
if (!this.isShaderActive)
return;
const now = performance.now();
if (this.properties.lastRenderTime > 0) {
const delta = (now - this.properties.lastRenderTime) / 1000;
this.properties.shaderTime += delta * this.properties.shaderSpeed;
}
this.properties.lastRenderTime = now;
};
nodeType.prototype.drawShader = function (program) {
const gl = this.gl;
if (!gl)
return;
gl.useProgram(program);
const locs = {
time: gl.getUniformLocation(program, 'u_time'),
intensity: gl.getUniformLocation(program, 'u_intensity'),
scale: gl.getUniformLocation(program, 'u_scale'),
octaves: gl.getUniformLocation(program, 'u_octaves'),
shapeType: gl.getUniformLocation(program, 'u_shapeType'),
shapeStrength: gl.getUniformLocation(program, 'u_shapeStrength'),
warpStrength: gl.getUniformLocation(program, 'u_warpStrength'),
phaseShift: gl.getUniformLocation(program, 'u_phaseShift'),
colorScheme: gl.getUniformLocation(program, 'u_colorScheme'),
};
gl.uniform1f(locs.time, this.properties.shaderTime);
gl.uniform1f(locs.intensity, this.properties.shaderColorIntensity);
gl.uniform1f(locs.scale, this.properties.shaderScale);
gl.uniform1f(locs.octaves, this.properties.shaderOctaves);
gl.uniform1i(locs.shapeType, SHAPE_TYPE_MAP[this.properties.shaderShapeType] || 0);
gl.uniform1f(locs.shapeStrength, this.properties.shaderShapeStrength);
gl.uniform1f(locs.warpStrength, this.properties.shaderWarpStrength);
gl.uniform1f(locs.phaseShift, this.properties.shaderPhaseShift);
gl.uniform1i(locs.colorScheme, COLOR_SCHEME_MAP[this.properties.colorScheme] || 0);
const positionLocation = gl.getAttribLocation(program, 'a_position');
gl.enableVertexAttribArray(positionLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
};
nodeType.prototype.renderShader = function () {
if (!this.isShaderActive || !this.gl || !this.shaderPrograms)
return;
const gl = this.gl;
const currentShaderType = this.properties.shaderType;
if (!this.shaderPrograms[currentShaderType]) {
this.loadShader(currentShaderType);
gl.clearColor(0.1, 0.1, 0.1, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
return;
}
const program = this.shaderPrograms[currentShaderType];
if (!program)
return;
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
this.updateAnimationTime();
this.drawShader(program);
};
nodeType.prototype.onResize = function (size) {
this._isResizing = true;
size[0] = Math.max(this.min_width || 300, size[0]);
const baseSize = origComputeSize ? origComputeSize.call(this, [size[0], 0]) : [size[0], 0];
const baseHeight = baseSize[1];
const minTotalHeight = baseHeight + 50;
size[1] = Math.max(minTotalHeight, size[1]);
if (this.properties.shaderVisible) {
this.shaderHeight = Math.max(50, size[1] - baseHeight);
this.resizeShaderCanvas(size[0], this.shaderHeight);
}
this.size = size;
this._isResizing = false;
this.setDirtyCanvas(true, true);
};
nodeType.prototype.onDrawForeground = function (ctx) {
if (this.properties?.shaderVisible && this.shaderCanvas && !this.flags?.collapsed) {
this.isShaderActive = true;
if (!this.animationFrameId) {
const animate = () => {
if (!this.isShaderActive || !this.properties.shaderVisible) {
this.animationFrameId = null;
return;
}
this.renderShader();
this.setDirtyCanvas(true, false);
this.animationFrameId = requestAnimationFrame(animate);
};
animate();
}
const widgetBottom = this.widgets?.length ? 40 + this.widgets.length * 24 : 40;
const shaderY = widgetBottom + 10;
const shaderHeight = Math.max(50, this.size[1] - shaderY);
try {
ctx.drawImage(this.shaderCanvas, 0, shaderY, this.size[0], shaderHeight);
}
catch (e) { /* ignore */ }
if (origOnDrawForeground)
origOnDrawForeground.call(this, ctx);
}
else {
if (origOnDrawForeground)
origOnDrawForeground.call(this, ctx);
this.isShaderActive = false;
if (this.animationFrameId) {
cancelAnimationFrame(this.animationFrameId);
this.animationFrameId = null;
}
}
};
nodeType.prototype.computeSize = function (size) {
size = size || [this.size?.[0] || 300, 0];
if (this.flags?.collapsed) {
size[0] = 190;
size[1] = 40;
return size;
}
if (origComputeSize)
origComputeSize.call(this, size);
const baseHeight = size[1];
if (this.properties?.shaderVisible && !this._isResizing) {
const currentShaderHeight = this.shaderHeight || 200;
size[1] = baseHeight + Math.max(50, currentShaderHeight);
}
return size;
};
nodeType.prototype.onRemoved = function () {
if (origOnRemoved)
origOnRemoved.call(this);
if (this.animationFrameId) {
cancelAnimationFrame(this.animationFrameId);
this.animationFrameId = null;
}
if (this.gl) {
for (const programType in this.shaderPrograms) {
if (this.shaderPrograms[programType])
this.gl.deleteProgram(this.shaderPrograms[programType]);
}
if (this.loadingIndicatorProgram) {
this.gl.deleteProgram(this.loadingIndicatorProgram);
this.loadingIndicatorProgram = null;
}
if (this.positionBuffer)
this.gl.deleteBuffer(this.positionBuffer);
this.shaderPrograms = {};
this.positionBuffer = null;
this.gl = null;
}
this.shaderSources = {};
this.shaderCanvas = null;
this.pendingShaders = [];
this.loadingShader = false;
};
nodeType.prototype.startBackgroundLoading = function () { return; };
nodeType.prototype.onConfigure = function (info) {
if (origOnConfigure)
origOnConfigure.apply(this, arguments);
if (this.widgets && this.properties) {
const updateWidget = (name, prop) => {
const w = this.widgets?.find(w => w.name === name);
if (w && this.properties[prop] !== undefined)
w.value = this.properties[prop];
};
updateWidget("Show Shader", "shaderVisible");
updateWidget("Show Tooltips", "tooltipsVisible");
updateWidget("Shader Noise Type 🔄", "shaderType");
updateWidget("Shape Mask Type 🔄", "shaderShapeType");
updateWidget("Color Scheme 🔄", "colorScheme");
updateWidget("Noise Scale 🔄", "shaderScale");
updateWidget("Octaves 🔄", "shaderOctaves");
updateWidget("Warp Strength 🔄", "shaderWarpStrength");
updateWidget("Shape Mask Strength 🔄", "shaderShapeStrength");
updateWidget("Phase Shift 🔄", "shaderPhaseShift");
updateWidget("Animation Speed 🖥️", "shaderSpeed");
updateWidget("Color Intensity 🔄", "shaderColorIntensity");
updateWidget("Pixel Resolution 🖥️", "shaderResolutionScale");
}
if (this.properties?.shaderVisible) {
const baseSize = origComputeSize ? origComputeSize.call(this, [this.size[0], 0]) : [this.size[0], 0];
this.shaderHeight = this.shaderHeight || 200;
const expectedHeight = baseSize[1] + this.shaderHeight;
if (Math.abs(this.size[1] - expectedHeight) > 1) {
this.size[1] = expectedHeight;
this.resizeShaderCanvas(this.size[0], this.shaderHeight);
this.setDirtyCanvas(true, true);
}
this.isShaderActive = true;
}
else {
this.isShaderActive = false;
}
};
nodeType.prototype.getExtraMenuOptions = function (canvas, options) {
if (origGetExtraMenuOptions)
origGetExtraMenuOptions.call(this, canvas, options);
options.push(null, {
content: this.properties.shaderVisible ? "Hide Shader Preview" : "Show Shader Preview",
callback: () => {
this.properties.shaderVisible = !this.properties.shaderVisible;
const shaderWidget = this.widgets?.find(w => w.name === "Show Shader");
if (shaderWidget)
shaderWidget.value = this.properties.shaderVisible;
const baseSize = origComputeSize ? origComputeSize.call(this, [this.size[0], 0]) : [this.size[0], 0];
if (this.properties.shaderVisible && this.gl) {
this.shaderHeight = this.shaderHeight || 200;
this.size[1] = baseSize[1] + this.shaderHeight;
this.resizeShaderCanvas(this.size[0], this.shaderHeight);
this.isShaderActive = true;
this.properties.lastRenderTime = 0;
}
else {
this.size[1] = baseSize[1];
this.isShaderActive = false;
if (this.animationFrameId) {
cancelAnimationFrame(this.animationFrameId);
this.animationFrameId = null;
}
}
this.setDirtyCanvas(true, true);
}
});
return options;
};
}
});
//# sourceMappingURL=shader_renderer.js.map