screentinker/server
ScreenTinker 95b8d1b293 Export shared modules to the browser even when Node is in the page
Transitions have never run on BrightSign, and it was never a GPU problem.

`transitionRuntimeReady()` is a presence check on three globals and touches no
WebGL at all. A BrightSign roHtmlWidget is created with `nodejs_enabled: true`,
which puts Node's `module` into classic-script scope — so every shared module
that exported with an `else` took the CommonJS branch and never assigned its
browser global. The runtime was absent before WebGL was ever asked a question.

This is deducible from the fleet without touching the hardware: the player
pushes system.reboot / display.power / display.resolution / system.self_update
only behind BS.hasHost(), which needs require('@brightsign/messageport') to
resolve. Our XT245's stored capability row carries all four, so Node
integration was live in that page, so the CommonJS branch was taken.

Transitions are the least of it. schedule-eval.js had the same shape, and the
player falls back to "always active" when ScheduleEval is missing — so per-item
DAYPARTING silently stopped applying on that platform and scheduled content
played outside its window with nothing in any log. player-media-health.js the
same. Four files, all fixed by exporting to BOTH targets rather than either/or.

media-mute.js, orientation-style.js and wall-geometry.js already assigned their
globals in a separate unconditional block and were never affected; the audit
that reached me claimed all seven, and reading them is what separated the four
from the three.

THE GUARD, WITHOUT WHICH THE ABOVE IS A REGRESSION.

Restore the globals alone and BrightSign starts attempting video wipes it
cannot supply. On a hardware video plane drawImage(video) succeeds, throws
nothing, and paints a fully TRANSPARENT frame — so the wipe fades from nothing,
behind a video plane that is still lit. Worse than the hard cut it replaces.

The discriminator already existed: videoFrameIsCapturable() probes ALPHA, so a
genuine fade-to-black still reads as captured. It was wired into the screenshot
path and not this one, which asked isMediaReadable() — a CORS question, "am I
allowed to read this", not "did any pixels arrive". Both the outgoing frame and
the incoming warm-play snapshot now consult it, cached per platform, defaulting
to available while undetermined so a cold start is not crippled.

Net effect on BrightSign: image-to-image transitions light up, anything
involving video hard-cuts honestly, and dayparting starts working.

Full video transitions are reachable later — BrightSign documents that video
"captured as a canvas for WebGL processing must be routed to the GPU" via a
per-element hwz="off", which keeps hardware decode at an 8-bit/1080p ceiling.
That needs the hardware to validate and is not in this change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014skWYXJUWhF73EvNPgB2AS
2026-08-07 10:36:50 -05:00
..
config fix(logging): gate CF-Connecting-IP on a Cloudflare peer, not any trusted proxy 2026-07-26 10:23:04 -05:00
db Show a panel's IPv6, and size the pairing code to the screen it is on 2026-08-07 08:06:45 -05:00
lib Export shared modules to the browser even when Node is in the page 2026-08-07 10:36:50 -05:00
middleware Merge branch 'fix/recovery-grants' into release/auth-campaign 2026-07-26 16:22:59 -05:00
player Export shared modules to the browser even when Node is in the page 2026-08-07 10:36:50 -05:00
routes Show a panel's IPv6, and size the pairing code to the screen it is on 2026-08-07 08:06:45 -05:00
scripts fix(content+android): rotation-aware media — portrait upright on dashboard AND player (#170) (#172) 2026-07-12 22:05:11 -05:00
services #240: stop the morning wave buying itself a blocking checkpoint 2026-08-06 20:22:21 -05:00
test Export shared modules to the browser even when Node is in the page 2026-08-07 10:36:50 -05:00
ws Show a panel's IPv6, and size the pairing code to the screen it is on 2026-08-07 08:06:45 -05:00
.gitignore feat(email): Microsoft Graph send + alert spam protection + preferences UI 2026-05-12 18:16:40 -05:00
config.js #240: stop the morning wave buying itself a blocking checkpoint 2026-08-06 20:22:21 -05:00
package-lock.json chore(release): v1.9.31 2026-08-06 21:08:14 -05:00
package.json chore(release): v1.9.31 2026-08-06 21:08:14 -05:00
server.js Backfill missing thumbnails at boot, and say when ffmpeg is absent 2026-08-07 09:30:32 +01:00
smoke-ui.js Keep the smoke test out of npm test, and update the lockfile 2026-07-28 20:34:34 -05:00
version.js chore(version): single-source VERSION, env-configurable data paths, bump tooling 2026-06-10 12:56:03 -05:00