Fix 22 bugs, migrate to TypeScript, and modernise the toolchain - #251
Open
emshotton wants to merge 4 commits into
Open
Fix 22 bugs, migrate to TypeScript, and modernise the toolchain#251emshotton wants to merge 4 commits into
emshotton wants to merge 4 commits into
Conversation
emshotton
force-pushed
the
modernise-toolchain
branch
from
August 17, 2026 05:45
1b3c636 to
ac20c64
Compare
Bug fixes (each with a regression test; 34 tests added, 61 -> 95): - playbackRate/volume setters now match nodes via instanceof MediaNode (minification-safe, covers AudioNode and custom subclasses) - audio() passes the real element cache instead of a never-assigned field - ProcessingNode binds Image-property samplers with the 0-based texture unit index instead of the TEXTURE0 enum - RenderGraph places index-connections on the port matching their zIndex - SourceNode._seek updates the clock before the waiting-state early return - new VideoContext.destroy() + UpdateablesManager.unregister() fix the permanent retention of every context by the module-level update loop - ProcessingNode.destroy() no longer clobbers its main output texture; also deletes the vertex buffer - ImageNode TYPE corrected from copy-pasted "CanvasNode"; user-supplied elements no longer crash _load and become ready; static image textures upload once instead of every frame - durationchange no longer re-fires every frame for endless sources - snapshot() records true input port indexes; element.onerror cleared on unload; destroyed nodes refuse start(); paused nodes unload on end; reset() clears callbacks before firing updates; unknown named ports on unlimited nodes throw; update loop starts without Worker/visibility API - exceptions are real Error subclasses; shader failures throw them TypeScript & toolchain migration: - all of src/ converted to strict TypeScript; tsc type-checks and emits declarations, Babel 7 (+preset-typescript) transpiles - 44 .frag/.vert shader files inlined as template literals (removes raw-loader, per-definition package.json stubs, and the jest glsl mock) - Jest 29 aligned (drops jest-cli 23 / babel-jest 23; explicit jsdom), ESLint 8 + @typescript-eslint, Prettier 3, TypeDoc replaces jsdoc, husky removed, CI on Node 20 with a typecheck step - packaging: UMD (main, unchanged path), per-module ESM (module/exports, sideEffects: false), generated .d.ts (types); zero runtime deps; browserslist "defaults" (drops IE11) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…eated unload in CanvasNode Adds 30 tests (95 -> 125) covering the video element pool's autoplay contract, CanvasNode's load/seek/ended lifecycle, and MediaNode's playbackRate, stretchPaused, buffering, loop, element-cache, URL/ MediaStream source, error, ended and seek branches. Overall statement coverage rises from 57.8% to 65.7% (branches 48.1% -> 60.8%). Writing the CanvasNode ended-state test exposed a bug: after passing its stop time the node called _unload() on every frame, firing the "destroy" callback repeatedly, because its guard (_element !== undefined) never becomes false for a user-supplied canvas. Fixed with the same _loadCalled guard used by MediaNode. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
GConf was removed from Ubuntu, so this step now fails on ubuntu-latest (24.04) before any tests run. Nothing needs it: the unit and integration suites are Node/jsdom only, and Cypress 4's Electron 8 / Chromium 80 does not link against GConf. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Chrome 137+ disables the SwiftShader software-WebGL fallback by
default, so on GitHub's GPU-less runners getContext("webgl") returns
null and every visual test fails with "Cannot read properties of
undefined (reading 'createTexture')". Pass --enable-unsafe-swiftshader
via the before:browser:launch hook to restore it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
emshotton
force-pushed
the
modernise-toolchain
branch
from
August 17, 2026 05:49
ac20c64 to
be6b113
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hey! I'm the original author of this library, I was delighted to see it was still being maintained and used after I left the BBC. Looks like it's been a few years since it's been updated, so I thought I'd have a go at revisiting it with Claude Code to see what could be fixed up. This PR does a bunch of modernization, bug fixing, and adding of new tests with only a relatively minor breaking change to the API (
VideoContext.exceptionsare nowErrorsubclasses).This ended up being a bit of a monster of a PR, and I'd be happy to split it into more reasonable sized chunks if preferred.
Summary
This PR does three related pieces of work, verified end-to-end at each step:
src/to strict TypeScript (compiled by Babel, type-checked bytsc).d.tstypesTests grow from 61 to 125 (all passing);
tsc --noEmitand ESLint are clean.Bug fixes (each with a regression test)
API correctness
playbackRate/volumesetters now match nodes withinstanceof MediaNodeinstead of a fragile constructor-name check, so they work on subclassesaudio()now passes the media element cache (previously silently dropped)createImageSourceNodeforwards its arguments correctlyVideoContext.destroy()releases the update-loop registration and the global debug ref;reset()clears callbacks before the final update so staleUPDATEcallbacks don't fireendOnLastSourceEndgetter; WebGL context creation falls back toexperimental-webglwith the supplied context attributesRender graph
getInputsForNodeplaces z-index connections on the port matching their index (previously order-dependent); out-of-range indexes fall back to the first free portConnectExceptioninstead of silently mis-connectingErrorsubclasses (stack traces,instanceofworks)Source nodes
start(offset)is computed from the seeked timestart()/startAt()refuse to re-sequence a destroyed nodedurationchangefires once when derived from the element, not on every frame for endless sources; mediaerrorhandlers are detached on unload so they can't fire on dead nodesonloadProcessing nodes
_renderbound textures with the wrong texture-unit value (enum instead of index) — inputs beyond the first could sample the wrong texturedestroy()deleted the wrong texture reference and leaked the vertex bufferTypeScript & toolchain
anyescapes, honest casts are commentedraw-loaderand the per-definitionpackage.jsonstubs)@babel/preset-env+preset-typescript), Jest 23 → 29 (jsdom), ESLint 8 +@typescript-eslint, Prettier 3, JSDoc → TypeDoc, husky removed (CI is the gate), CI on Node 20 with atypecheckstepregenerator-runtimeno longer needed)Packaging
main: UMD bundle (unchanged path), now Node-require safe (globalObject: "this")module+exportsmap: per-module ESM build (tree-shakeable,sideEffects: false)types: generated.d.tsdeclarationsBreaking / behavioural changes
"defaults"— IE11 is droppedVideoContext.exceptionsare nowErrorsubclasses (message/stack behaviour changes if anyone matched on the old plain objects)Not included (deliberately)
cypress-image-snapshotreplacementTest plan
tsc --noEmitclean (strict mode).d.tsoutputs built and smoke-tested