when typed n, it says “failed to compile vertex shader
// night-mode.mjs
import { Color, Entity, Script } from 'playcanvas';
const gsplatVS = /* glsl */`
#include "gsplatCommonVS"
varying mediump vec2 gaussianUV;
varying mediump vec4 gaussianColor;
#ifndef DITHER_NONE
varying float id;
#endif
mediump vec4 discardVec = vec4(0.0, 0.0, 2.0, 1.0);
#ifdef PREPASS_PASS
varying float vLinearDepth;
#endif
uniform vec3 spherePositions[10];
uniform vec3 sphereColors[10];
uniform float nightFade;
uniform vec3 nightAmbient;
// linear/gamma
vec3 l2g(vec3 c) { return pow(c, vec3(1.0 / 2.2)); }
vec3 g2l(vec3 c) { return pow(c, vec3(2.2)); }
vec3 applyNightMode(vec3 clrIn, vec3 modelPos) {
if (nightFade == 0.0) {
return clrIn;
}
vec4 worldPos = matrix_model * vec4(modelPos, 1.0);
worldPos /= worldPos.w;
vec3 sum = vec3(0.0);
for (int i = 0; i < 10; ++i) {
vec3 pos = spherePositions[i];
vec3 clr = sphereColors[i];
sum += g2l(clr) * 1.1 / pow(length(pos - worldPos.xyz), 2.0);
}
// blend in linear space
return l2g(g2l(clrIn) * mix(vec3(1.0), g2l(nightAmbient) + sum, nightFade));
}
void main(void) {
// SENTINEL_2026_05_17_v3
// read gaussian details
SplatSource source;
if (!initSource(source)) {
gl_Position = discardVec;
return;
}
vec3 modelCenter = getCenter();
SplatCenter center;
if (!initCenter(modelCenter, center)) {
gl_Position = discardVec;
return;
}
// project center to screen space
SplatCorner corner;
if (!initCorner(source, center, corner)) {
gl_Position = discardVec;
return;
}
// read color
vec4 clr = getColor();
#if GSPLAT_AA
// apply AA compensation
clr.a *= corner.aaFactor;
#endif
// evaluate spherical harmonics
#if SH_BANDS > 0
// calculate the model-space view direction
vec3 dir = normalize(center.view * mat3(center.modelView));
// read sh coefficients
vec3 sh[SH_COEFFS];
float scale;
readSHData(sh, scale);
// evaluate
clr.xyz += evalSH(sh, dir) * scale;
#endif
// apply night mode
clr.xyz = applyNightMode(clr.xyz, modelCenter);
clipCorner(corner, clr.w);
// write output
gl_Position = center.proj + vec4(corner.offset, 0.0);
gaussianUV = corner.uv;
gaussianColor = vec4(prepareOutputFromGamma(max(clr.xyz, 0.0), -center.view.z), clr.w);
#ifndef DITHER_NONE
id = float(source.id);
#endif
#ifdef PREPASS_PASS
vLinearDepth = -center.view.z;
#endif
}
`;
const lerp = (a, b, t) => a * (1 - t) + b * t;
const damp = (damping, dt) => 1 - Math.pow(damping, dt * 1000);
export class NightMode extends Script {
static scriptName = "nightMode";
/**
* @attribute
* @type Entity
*/
light;
/**
* @attribute
* @type Entity
*/
camera;
/**
* @attribute
* @type Entity
*/
splat;
/**
* @attribute
* @type Color
*/
nightAmbient = new Color(0);
/**
* @attribute
*/
emissiveIntensity = 10;
/**
* @attribute
*/
lightingIntensity = 1.23;
/**
* @attribute
*/
emissiveBloom = 0.05;
initialize() {
this.nightMode = false;
this.nightFade = 0;
this.app.on('toggle:night', () => {
this.nightMode = !this.nightMode;
const material = this.splat.gsplat.material;
material.shaderChunks.glsl.set('gsplatVS', gsplatVS);
material.shaderChunksVersion = '2.18';
material.update();
});
}
update(dt) {
const material = this.splat?.gsplat?.material;
if (!material) {
return false;
}
// update night fade
const target = this.nightMode ? 1 : 0;
if (Math.abs(this.nightFade - target) < 1e-06) {
this.nightFade = target;
} else {
this.nightFade = lerp(this.nightFade, target, damp(0.98, dt));
}
// get sphere positions
const spheres = this.app.root.findByTag('sphere');
this.light.light.intensity = 1 - this.nightFade;
this.camera.script.cameraEffects.bloom.intensity = lerp(0, this.emissiveBloom, this.nightFade);
const eintensity = this.emissiveIntensity;
const lintensity = this.lightingIntensity;
const positions = [];
const colors = [];
for (let i = 0; i < 10; ++i) {
const sphere = spheres[i];
if (!sphere) {
positions.push(0, 0, 0);
colors.push(0, 0, 0);
} else {
const pos = sphere.getPosition();
const { material } = sphere.render.meshInstances[0];
const { diffuse } = material;
positions.push(pos.x, pos.y, pos.z);
colors.push(diffuse.r * lintensity, diffuse.g * lintensity, diffuse.b * lintensity);
material.emissive.set(diffuse.r, diffuse.g, diffuse.b);
material.emissiveIntensity = this.nightFade * eintensity;
material.gloss = lerp(0.7, 0.3, this.nightFade);
material.update();
}
}
material.setParameter('spherePositions[0]', positions);
material.setParameter('sphereColors[0]', colors);
material.setParameter('nightFade', this.nightFade);
material.setParameter("nightAmbient", [this.nightAmbient.r, this.nightAmbient.g, this.nightAmbient.b]);
this.app.scene.skyboxIntensity = lerp(1.0, 0.2, this.nightFade);
this.app.fire('nightFade', this.nightFade);
}
};
OK. I fixed it. I don’t know whether this could be permanent, nor guaranteed to work for later. But it works for Engine 2.18.1.
Just replace the current night-mode.mjs with the above code.
Which hardware/os/browser are you using? This works fine on my Mac M4 under chrome and safari.
Also, what is the console output for the failure?
Following was F12 messages.=============== Powered by PlayCanvas 2.18.1 5e45104
messenger.ts:104 messenger connected
debug.js:14 DEPRECATED: pc.createShaderFromCode has been deprecated. Use ShaderUtils.createShader instead.
deprecated @ debug.js:14Understand this warning
viewport-error-console.ts:186 Failed to compile vertex shader:
ERROR: 0:664: ‘readCenter’ : no matching overloaded function found
ERROR: 0:664: ‘=’ : dimension mismatch
ERROR: 0:664: ‘=’ : cannot convert from ‘const mediump float’ to ‘highp 3-component vector of float’
ERROR: 0:680: ‘readColor’ : no matching overloaded function found
ERROR: 0:680: ‘=’ : dimension mismatch
ERROR: 0:680: ‘=’ : cannot convert from ‘const mediump float’ to ‘highp 4-component vector of float’
ERROR: 0:690: ‘readSHData’ : no matching overloaded function found
ERROR: 0:701: ‘constructor’ : too many arguments
ERROR: 0:703: ‘prepareOutputFromGamma’ : no matching overloaded function found
ERROR: 0:703: ‘constructor’ : not enough data provided for construction
It was Windows. Chrome. Engine 2.18.1
