Problem
`Camera3d` (#1464) silently does the wrong thing under the Canvas renderer. Its perspective projection + depth-test-driven painter sort presuppose a WebGL context — the Canvas backend has no `gl`, no depth buffer, no `drawMesh` path. Today the engine just runs and produces a broken picture (no 3D, no mesh rendering, sometimes a blank canvas), with no error to tell the dev why.
Repro
```ts
const app = new Application(800, 600, {
renderer: video.CANVAS, // ← explicit Canvas
cameraClass: Camera3d, // ← Camera3d
});
```
→ no error, scene renders with no perspective, meshes invisible, depth-sort ineffective. User has no clue why.
Same thing happens when `video.AUTO` falls back to Canvas (WebGL unavailable / failIfMajorPerformanceCaveat = true on a low-perf device + Camera3d in the app's cameraClass).
Proposed
In the `Camera3d` constructor (or in `Application`'s camera-class instantiation path), check the active renderer at construction time and throw a clear error if it isn't a `WebGLRenderer`:
```ts
if (!(video.renderer instanceof WebGLRenderer)) {
throw new Error(
"Camera3d requires the WebGL renderer (Canvas backend lacks the " +
"depth buffer + 3D projection path Camera3d depends on). Set " +
"{ renderer: video.WEBGL } on your Application — or fall back to " +
"Camera2d if WebGL isn't available on the target device."
);
}
```
Fail-fast at construction time is better than a silently broken scene at runtime.
Open question
Should the check be on `Camera3d` itself (constructor-time, requires Camera3d to import the renderer class — possible circular dep) or on `Application` (which already mediates renderer + cameraClass)? Probably Application — cleaner separation, no new import in Camera3d.
Scope
- ~10 lines of code
- One regression spec: `new Application({ renderer: video.CANVAS, cameraClass: Camera3d })` must throw with a useful message
- CHANGELOG entry under `### Changed` (behavioural change — silent fallback → loud error)
Related
Problem
`Camera3d` (#1464) silently does the wrong thing under the Canvas renderer. Its perspective projection + depth-test-driven painter sort presuppose a WebGL context — the Canvas backend has no `gl`, no depth buffer, no `drawMesh` path. Today the engine just runs and produces a broken picture (no 3D, no mesh rendering, sometimes a blank canvas), with no error to tell the dev why.
Repro
```ts
const app = new Application(800, 600, {
renderer: video.CANVAS, // ← explicit Canvas
cameraClass: Camera3d, // ← Camera3d
});
```
→ no error, scene renders with no perspective, meshes invisible, depth-sort ineffective. User has no clue why.
Same thing happens when `video.AUTO` falls back to Canvas (WebGL unavailable / failIfMajorPerformanceCaveat = true on a low-perf device + Camera3d in the app's cameraClass).
Proposed
In the `Camera3d` constructor (or in `Application`'s camera-class instantiation path), check the active renderer at construction time and throw a clear error if it isn't a `WebGLRenderer`:
```ts
if (!(video.renderer instanceof WebGLRenderer)) {
throw new Error(
"Camera3d requires the WebGL renderer (Canvas backend lacks the " +
"depth buffer + 3D projection path Camera3d depends on). Set " +
"{ renderer: video.WEBGL } on your Application — or fall back to " +
"Camera2d if WebGL isn't available on the target device."
);
}
```
Fail-fast at construction time is better than a silently broken scene at runtime.
Open question
Should the check be on `Camera3d` itself (constructor-time, requires Camera3d to import the renderer class — possible circular dep) or on `Application` (which already mediates renderer + cameraClass)? Probably Application — cleaner separation, no new import in Camera3d.
Scope
Related