Playground: load earcut and procedural textures, and provide name to test scripts - #1823
Conversation
…o test scripts
Three unrelated-looking test failures all had the same root cause: the native
Playground provides a smaller browser environment than the web Playground, so
scripts that work on the web die here on a missing global.
- `earcut`: PolygonMeshBuilder looks `earcut` up as a global at triangulation
time rather than importing it, so any polygon scene fails with
`ReferenceError: earcut is not defined`. Pinned to ^2.2.4 because that is the
last line shipping a UMD build (`dist/earcut.min.js`); 3.x is ESM-only and
cannot be loaded by the plain-script loader.
- `babylonjs-procedural-textures`: the procedural texture classes
(WoodProceduralTexture, BrickProceduralTexture, ...) live in their own package
which was never loaded, so those scenes failed with
`BABYLON.WoodProceduralTexture is not a constructor`.
- `name`: some scripts reference `name` without declaring it. In a browser that
silently resolves to window.name (""), so the bug is invisible there but
throws `ReferenceError: name is not defined` here. Declared in the scope that
encloses the eval so a direct eval resolves it exactly as the web does.
Deliberately *not* defined as a real global: doing that breaks the Babylon UMD
bundles, which probe for `name` during evaluation and throw at load time.
None of this is renderer-specific; it fixes the same scenes on both the bgfx and
the WebGPU/Dawn paths.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 88569c10-a7ff-4373-9a58-afa9c68b8c09
There was a problem hiding this comment.
Pull request overview
Updates the native Playground harness to more closely match the web Playground’s “ambient browser globals” by bundling additional Babylon-related scripts (earcut + procedural textures) and by providing a name binding visible to directly-evaluated test scripts, reducing harness-specific test failures across backends.
Changes:
- Add
earcut.min.jsandbabylonjs.proceduralTextures.jsto the native Playground script bundle and bootstrap load order. - Ensure Android asset packaging and the nightly download script include the new Babylon procedural textures artifact.
- Add a scoped
var name = ""binding around directeval()execution paths invalidation_native.jsto match browser behavior.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| Apps/scripts/getNightly.js | Downloads the procedural textures library artifacts alongside other Babylon nightly files. |
| Apps/Playground/Shared/PlaygroundScripts.cpp | Loads earcut.min.js before polygon scenes run, and loads procedural textures after BABYLON is initialized. |
| Apps/Playground/Scripts/validation_native.js | Introduces a local name binding in eval scopes to prevent ReferenceError: name is not defined for browser-authored scripts. |
| Apps/Playground/CMakeLists.txt | Adds earcut + procedural textures to the packaged script set for native Playground builds. |
| Apps/Playground/Android/app/build.gradle | Copies earcut + procedural textures into Android assets for the Playground app. |
| Apps/package.json | Adds babylonjs-procedural-textures and earcut dependencies for bundling/packaging. |
| Apps/package-lock.json | Locks the new dependencies and their resolved versions. |
Files not reviewed (1)
- Apps/package-lock.json: Generated file
… bundle Addresses review feedback on the earcut/procedural-textures change. package.json pinned babylonjs-procedural-textures with a caret while the PR called for an exact pin; on ^9.15.0 npm resolves 9.20.0 and nests a second full copy of babylonjs underneath it. Pin it exactly, in both package.json and the lock file's root dependency range, so regenerating the lock file cannot drift. getNightly replaces seven babylon*.js bundles but only babylon.max.js was down-leveled to ES5 afterwards, so the other six ran un-transpiled on Chakra -- and any bundle added to BABYLON_SCRIPTS later would silently inherit the same gap. Derive the down-level list from the download table itself and run it from getNightly.js, so the two can no longer disagree. Source maps are excluded by the .js anchor. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 88569c10-a7ff-4373-9a58-afa9c68b8c09
|
Thanks — all three review comments were valid; pushed in e421e9a. Exact pin for Down-leveling more than Rather than lengthen the hardcoded argument list (which is what let the two drift apart in the first place), the down-level list is now derived from the download table inside CI note: |
Review feedback from bghgary on BabylonJS#1823. The earcut comment keeps only the two facts a reader needs (the global lookup and the failure without it), and the procedural textures comment is dropped: the seven separate-package loads above it carry no comment either, and the two that do state something the code cannot show. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 88569c10-a7ff-4373-9a58-afa9c68b8c09
|
Thanks -- all four addressed.
One measured correction on that last one: Re-requesting review. |
The "Update scripts from snapshot" step refills **every** `babylon*`
file in the two Babylon Native artifact directories from the CDN
snapshot:
```bat
set destDir=..\BabylonNativeNightlyPlayground\RelWithDebInfo\Scripts
for /f %%i in ('dir /b %destDir%\babylon*') do (
unzip -p snapshot.zip "**%%i" > %destDir%\%%i
)
```
...but the downlevel that follows names a single file:
```bat
npm run downlevel:native-scripts -- ..\BabylonNativeNightlyPlayground\RelWithDebInfo\Scripts\babylon.max.js
```
So the refill is a glob and the downlevel is an allowlist of one. Any
bundle added to the Native script set later gets refilled from the
snapshot and then executed **un-downleveled**, which on Chakra surfaces
as a parse error at load with nothing pointing at the cause.
This passes the directory instead. `scripts/downlevelNativeScripts.mjs`
already walks a directory and selects files itself with
`/^babylon.*\.js$/i` — the same set the refill loop uses — so no change
to the script is needed.
### Please note: this is not a pure no-op
Six bundles are currently refilled from the snapshot but never
downleveled, and this makes them transpiled too. Syntax actually present
in each bundle on the CDN today:
| bundle | downleveled today | `?.` | `#priv` | `**` | `async` |
`function*` |
|---|---|---|---|---|---|---|
| `babylon.max.js` | **yes** | 19 | 2 | 74 | 1 | 631 |
| `babylonjs.loaders.js` | no | 2 | 0 | 0 | 0 | 148 |
| `babylonjs.serializers.js` | no | 2 | 0 | 0 | 0 | 62 |
| `babylonjs.addons.js` | no | 1 | 0 | 6 | 0 | 17 |
| `babylonjs.materials.js` | no | 0 | 0 | 3 | 0 | 14 |
| `babylon.gui.js` | no | 0 | 0 | 0 | 0 | 18 |
| `babylonjs.proceduralTextures.js` | n/a (not yet shipped) | 0 | 0 | 0
| 0 | 0 |
All seven are emitted at an ES2015 target, so transpiling them is the
intended direction rather than a workaround — but it is a behavior
change, and it costs some CI time. Flagging it explicitly rather than
describing this as a no-op.
### Verification
Ran the existing script against a directory laid out like the artifact:
```
babylon.max.js -> downleveled (var / function / Math.pow)
babylonjs.proceduralTextures.js -> downleveled (var / function)
babylon.max.js.map -> untouched (.js anchor excludes maps)
earcut.min.js -> untouched (not babylon*)
ammo.js -> untouched (not babylon*)
```
`ci-monorepo.yml` still parses as YAML.
### Context
Prompted by BabylonJS/BabylonNative#1823, which adds
`babylonjs.proceduralTextures.js` to the Playground script set. Per
review there, this needs to land first: naming the new file on this side
would fail until it exists in the Native artifact, whereas globbing the
directory is correct both before and after.
Co-authored-by: Branimir Karadzic <branimirkaradzic@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 88569c10-a7ff-4373-9a58-afa9c68b8c09
|
The blocker is cleared: BabylonJS/Babylon.js#18799 is merged, so the nightly now downlevels every |
Three test failures on the native Playground turned out to have the same root cause: the native harness provides a smaller browser environment than the web Playground, so scripts that work on babylonjs.com die here on a missing global. None of it is renderer-specific, so this fixes the same scenes on both the bgfx and the WebGPU/Dawn paths.
earcut is not definedPolygonMeshBuilderresolvesearcutas a global at triangulation time rather than importing it, so any scene that builds a polygon throws. The web Playground loads earcut as a separate script; we never did.Pinned to
^2.2.4deliberately, for two reasons — 3.x does shipdist/earcut.min.js, so "no UMD build" is not one of them:.earcut = e()); 3.x assigns a namespace object (.earcut = {}).PolygonMeshBuildercallsearcut(...), so 3.x throws at triangulation time.cdn.babylonjs.com/earcut.min.js, whichplayground/index.htmlloads, is itself 2.x (6,519 bytes, global-is-the-function).Thanks to @bghgary for catching the original, incorrect rationale.
BABYLON.WoodProceduralTexture is not a constructorThe procedural texture classes live in their own
babylonjs-procedural-texturespackage, which was never in the bundle. The existing config even documents this — one test is disabled with the reason "BABYLON.NormalMapProceduralTexture is not included in the native script bundle".Wired into
BABYLON_SCRIPTS,PlaygroundScripts.cpp, the Android asset copy, andgetNightly.jsso it stays in step with the other Babylon packages. Pinned to9.15.0to match every otherbabylonjs-*entry in the lock file — on^9.15.0npm resolves it to 9.20.0 and then nests a second full copy ofbabylonjsunder it.name is not definedSome scripts reference a bare
namewithout declaring it. In a browser that silently resolves towindow.name(""), so the bug is invisible on the web but throws here.Fixed by declaring
var name = ""in the function that encloses theeval. Because those are direct evals, the evaluated script sees that scope and resolvesnameexactly as it would on the web — without leaking a real global, and without rewriting the script text (so line numbers in stack traces and any"use strict"prologue are preserved).Defining an actual global
nameis not an option, and I tried: it breaks the Babylon UMD bundles, which probe fornamewhile being evaluated.babylonjs.loaders.jsthen throwsError: Invalid argumentat load time and every test fails.Depends on
BabylonJS/Babylon.js#18799 must land first. The nightly's "Update scripts from snapshot" step refills every
babylon*file in the Native artifact from the CDN snapshot, but the downlevel that follows names onlybabylon.max.js— so a newly added bundle is refilled and then run un-downleveled. #18799 passes the directory instead, which is correct both before and after this PR.Validation
Full 680-test sweep on the Dawn/WebGPU backend, before vs. after:
Zero regressions.
Polygonflips to PASS outright;Procedural texturesandShow all procedural texturesgo from hard exceptions to rendering (they still miss the pixel threshold, tracked separately). The other two deltas (Iridescence NME,Sprite maps) are known order-dependent flakes, not caused by this change.