Repository navigation
v0.20: runtime subpaths, ESM-only distribution, demo-asset catalog and two-channel Pages - #861
Conversation
… site-build.json manifest
|
To use Codex here, create an environment for this repo. |
Bundle ReportChanges will increase total bundle size by 1.48MB (4.16%) ⬆️. This is within the configured threshold ✅ Detailed changes
Affected Assets, Files, and Routes:view changes for bundle: site-server-esmAssets Changed:
view changes for bundle: exo-esm-esmAssets Changed:
view changes for bundle: exo-esm-modules-esmAssets Changed:
|
…hem in the skip budget
…act the convolution example plays
…e demo-assets README
…sets and serve only its standard profile
…th keyboard shortcuts
…clear start and pause state
…interaction profiles
…their interaction profiles
…interaction profiles
…d the demo media in the loading guide
…nd fix the comparison layouts the captures exposed
Independent review of head
|
…el under the preview
…d format the sound loader reads
…with per-type previews, scoped loads and copyable snippets
…t it when unchanged code is run again
…he playground's Output panel
…built playground in Chromium
…ut panel open on Clear
…he backdrop or a shared video
ExoJS v0.20: hybrid runtime subpaths, ESM-only distribution, demo-asset catalog in the playground, two-channel Pages
Integration PR for the v0.20 migration on top of
cea66372352fb54238211295b22518fce49f531b(after #859 and #860). It carries the runtime/ESM, demo-asset and Pages workstreams and, since the last review ofcddba1d7d, the two CI repairs, the complete adoption of the demo catalog by the examples, playground and site, and an interaction and quality pass over every catalog example. Nothing is merged, published, deprecated, released or deployed by this PR.1. Package and export structure
@codexo/exojsships the runtime modules as Core subpaths from one tarball:@codexo/exojs/tilemap,/particles,/audio-fx,/physics,/tilemap-physics,/lighting,/pathfinding. Their sources stay private workspaces (@codexo/exojs-module-*); one tsc program and an AST specifier rewriter produce NodeNext-clean declarations; one Core instance per app.@codexo/exojs/debugis the single debug entry and also exportsPhysicsDebugDraw/PhysicsDebugDrawOptions.@codexo/exojs-demo-assets0.1.0 (Core peer0.20.x, independent version line): frozen flatdemoAssetsdescriptors,demoAssetCategories,createDemoAssets(baseUrl),createExtendedDemoAssets(baseUrl)from/extended,manifest.json,exojs-demo-assets-copybin.2. Packages that stay separate, and the legacy shims
@codexo/exojs-tiled,-ldtk,-aseprite,-react,create-exo-app,@codexo/exojs-build,@codexo/exojs-cli,@codexo/eslint-plugin-exojs. KTX2/Basis worker and WASM stay in Core;Assets,Spriteand the loader contracts are unchanged.@codexo/exojs-tilemap,-particles,-audio-fx,-physicsincl./debug,-tilemap-physics,-lighting,-pathfinding) are forwarder-only shims underpackages/legacy/peering on Core0.20.x. Deprecation text and a registry dry run are prepared; no registry action ran.3. CI repairs since
cddba1d7d./media/*: the demo-assets build generatesmedia/, but thedistartifact handed to the verify jobs carried onlydist/andpackages/*/dist/. The artifact now also carriespackages/exojs-demo-assets/media/; the export and publint stay as they were (09789eac1).legacy-shims-tarball.test.ts) form the Vitest projectrelease-dist, excluded from the unit lane and run in the build job withEXOJS_REQUIRE_PRODUCTION_BUILD=1(a missing dist fails) and ajunit-buildreport that the skip budget reads. No budget was added (77899e8d9). CI run 39664733145 on77899e8d9: all jobs green,verify (package)andskip-budgetincluded.4. Demo assets in examples, playground and site
import { demoAssets as assets } from '@codexo/exojs-demo-assets'and loads throughthis.loader.get(assets.x)/await this.loader.load(assets.x); formats whose adapters take a URL (tileMap,ldtkMap, textures with sampler options) use the descriptor's public.source. Noloader.basePath: 'assets/'and no globalassetsremain. The old hierarchical catalog (examples/assets/{assets,catalog,resolver,index},assets.json),assets-global.d.ts, its generator and drift test, the preview prelude, the shell injection and the string-path completion provider are removed. Guide snippets underexamples/guides/keep user-project paths on purpose (they teach a project's ownpublic/assets).vendor/exojs-demo-assets/esm/(catalog + declarations) andvendor/exojs-demo-assets/media/(standard profile). The preview import map maps@codexo/exojs-demo-assetsand/extended; Monaco loads its declarations through the existing extension-package path.assets.with 139 keys, the import specifier suggestsdemoAssets, no diagnostics on the import; a separate JavaScript model completesassets.too,videoHighResresolves toLeaflessAsset<Video>with its JSDoc; the visible suggest widget lists the catalog keys.demoAssets+demoAssetCategoriesand returned to the playground catalog; see section 7.shipprovenance is ExoJS original work (MIT), as feat(examples): playground quality and experience sweep #860 recorded when it replaced the 505 B chevron; the Kenney Simple Space attribution was a leftover of that chevron and no Simple Space pack exists in the vendor tree. Please confirm.soundImpactMetalHeavyadded because convolution-rooms plays it (161 standard files now).load()/init()example replaces the never-calledApplication.prepare(), and README listings are now type-checked; a "Bundlers" section states what a bundler does with the catalog (below).loading-and-resourcesgets "Demo media for prototypes";migration-v020no longer claims the examples are unchanged.5. Asset delivery and sizes
media/)assets/tree (old full copy ofexamples/assets)vendor/exojs-demo-assets/cddba1d7d: 441,109,574 B)examples/assets/is the authoring source of the package; the long source videos and the Kenney vendor packs remain for provenance and generators); only the delivery changed. The site'sexamples:syncno longer copiesexamples/assets, and the full release ZIP no longer packs it.vite buildof a one-sprite consumer emits the whole standard set (21,082,124 B; 96 files plus small ones inlined), because all descriptors live in one object. Tiled maps, LDtk projects and bitmap fonts keep relative sibling paths that a hashing bundler breaks; the README routes those through the copy command andcreateDemoAssets. The Vite dev server serves the media from the package correctly. This is documented, not changed: a per-asset module layout would be a new API decision.videoHighRes) and 60 fps SDR (videoHighFps) clips plus the demo loop; HDR10 stays extended-only and the video example remains honestly SDR.6. Example interaction and quality pass
Every one of the 110 catalog entries got a profile and a decision: 86 changed, 24 kept on purpose. A small typed helper
demoPanel()in@examples/runtime(choice / slider / toggle / actions / status, one value per control) replaces hand-written control plumbing; keyboard shortcuts callpanel.set()/panel.step(), so keys and controls share one state. Example sources shrank by about 1,070 lines net. Permanent key legends moved into the catalog descriptions (88 updated).Highlights:
Example-by-example audit (110 entries)
hello-worldresize-and-dprscene-less-apporb-dodgemultiple-scenesloading-screenasset-catalogspause-blurcustom-transitionlevel-loading-and-ownershipcached-assets-offlinekeyboardmouse-and-pointeraction-mappinggamepadkey-rebindingmultitouchhud-and-widgetssettings-menutext-entry-and-scrollingdialog-systemmulti-view-split-screensprite-basicsnested-transformspivot-and-anchorblendmodesmaskstexture-samplingworld-vs-screen-coordsparallax-starfieldpicture-in-picturemini-mapframe-animationtween-basicstween-chainseasing-curvesscreen-shake-on-explosiongamepad-spaceshipboss-intro-cinematicgraphics-gradienttypographic-stylingmultiline-and-wrapbitmap-text-basicmesh-textured-quadmesh-deformed-gridmesh-typed-uniformsbloom-filterblur-filtercolor-matrix-filtercrt-scanlinescustom-fragment-shadermetaballsrender-to-texturetrail-feedbackcolor-pipelinewater-mirrorvideo-drawablerender-pipelinecustom-triangle-renderermany-lightsshadow-casterslight-cookieslightmap-normalsradiance-roomsemitter-basicscursor-attractor-particlesfireworksbonfireaudio-reactive-particlesgpu-particlescustom-wgsl-moduleplay-soundsound-poolmusic-loopaudio-busescrossfade-tracksreverb-and-delaypcm-streamgpu-pcm-streamcompressorduckingconvolution-roomseffect-chainssignal-graphvocoderaudio-visualisationbeat-sync-pulselistener-and-sourcetiled-isometrichexagonal-gridtile-chunks-and-bandstiled-map-importldtk-world-importeditor-objects-gameplaygrid-navigationtilemap-navigationpaint-autotiled-roomtiled-infinite-mapworker-streamed-terrainrectangles-collisionsprite-follows-bodykinematic-movementcharacter-movementtiled-map-physics-actorjoint-driven-shadowspointer-and-hittestbackend-comparisonretained-containerimmediate-mode-renderingcoroutine-loadingBefore/after evidence: all 109 runnable examples were captured on the old
cddba1d7dsite (CI artifact) and on this head with the same smoke harness (Chromium, WebGL2); the side-by-side sheets, the Monaco capture and the Asset Browser capture are on a private evidence page shared with the maintainer: https://claude.ai/artifact/LG73qDaVtxq4ftGwAU2DJx (needs maintainer access).7. Playground: Output panel, Asset Browser and the fixes they exposed
Output panel (all examples)
site/src/lib/preview-console.ts: the parent patcheslog,info,debug,warnanderroron the preview iframe's ownconsole(same origin, nopostMessage) inonLoad, before the example's module is appended. Each patch calls the original first, so DevTools keeps every message. Uncaught errors and unhandled rejections arrive through the existingonerror/onunhandledrejectionhandlers and land in the same record.%s %d %i %f %o %O %c, several arguments, cross-realm errors by shape (stack as details), arrays, typed arrays, Map/Set, DOM nodes, circular references ([Circular]), throwing getters; depth 3, 20 items, 2,000 characters per message.useSyncExternalStore).console.errormoments earlier is upgraded in place instead of listed twice;console.erroralone stays an ordinary entry and the example keeps running. TypeScript diagnostics stay in the existing strip with the jump to the line; catalog and source load failures are pinned at the top of the panel.Output, error and warning badges, the latest message), collapsed by default and remembered per browser. Expanded: monospace list, Errors / Warnings / Info / Logs filters (aria-pressed), Copy, Clear, autoscroll that stops while you scroll up, stack details per entry, bounded height. Plain logs never open it; the first uncaught error of a run does, unless the visitor collapsed it during that run. It sits in the preview column in split and follows a swap, between preview and editor when stacked, and spans the width on phones. Logging never takes focus from the preview.Asset Browser (
debug-layer/asset-browser)/tools/asset-browser/pages that shipped in v0.19 are now plain redirects to the playground entry;EXAMPLE_TOOL_RELOCATIONS, the relocation branch inExampleBrowser, the tool page component and the playground's tool link are gone. Historical versions keep their own catalogs.demoPanel) and a "Loader holds N assets" list read fromloader.inspect().manifest.json(now vendored and in the preview import map). Spritesheets show the atlas with frame bounds, a tapped frame enlarged, and anAnimatedSpriteover the atlas's own animations or a chosen frame range with FPS, loop and scale; no animation is assumed when the atlas defines none. Tiled and LDtk maps render throughTileMapNodewith level choice, per-layer visibility and object shapes; tileset paths resolve against the catalog's absolute source. Sounds draw their waveform with the selected sprite clip highlighted; sounds and music play, pause and stop with volume and loop. Videos play, pause, stop, seek, mute and change speed, with resolution, codec, frame rate, pixel format and audio from the manifest; dynamic range is labelled as file metadata. Fonts and bitmap fonts render editable sample text at three sizes. Maps and atlases have a Data view with the raw JSON, truncated beyond 60,000 characters.this.loaderload, sampler choice astextureOptions, sprite scale, animation clip, map extension,onUnlock-gated playback, video options), with Copy. Only public APIs and the demo catalog; every generated variant is type-checked by the browser test.LoaderScopeof the scene. Selecting something else disposes the preview and destroys that scope, which cancels a load still in flight and frees what it held unless another scope holds it. A result that settles after a newer selection is disposed before it can show, play, mount controls or log. Nothing plays on selection; Play registers onapp.audio.onUnlock, and Stop and every switch remove that registration, so a start still waiting for the gesture never plays for another selection.destroy()bumps the generation and closes everything.Fixes found on the way
fix(demo-assets): the three sound-sprite sidecars (ui,impacts,digital) were{ sprites: { name: { start, duration } } }, but the sound loader reads{ name: { start, end } }, souiSoundSprite,impactsSoundSpriteanddigitalSoundSpritefailed to load. Converted, manifest regenerated, and the catalog test now checks every sidecar's format.fix(site): the playground's TypeScript defaults setnoEmit, sogetEmitOutputwas empty and an edited TypeScript example never reached the preview; Reload also did nothing when the code had not changed. TypeScript models now emit, and every run restarts the preview. The browser test exercises both.fix(audio): the input system cancelspointerdownon the canvas and stops its propagation, which also suppresses the compatibilitymousedown, so a mouse click on the canvas never unlocked audio. The unlock listeners now includepointerdown/pointerupand run in the capture phase; the regression test fails without the fix. Audio guide and JSDoc (API JSON regenerated) updated.chore(examples):no-consoleis off forexamples/**; the Output panel makes logging part of how an example explains itself.Logging in examples
Keyboard (
KeyDown: Space,Action: Recentre, held-set changes), Action Mapping (resolved move direction and pulse), Pointer and Hit Testing (which ship a tap hit, where a drag ended, front changes), Drag and Throw Physics (grab, release speed, floor contacts fromonCollisionStart), Settings Menu (toggle, theme and reset; not the volume slider, which reports every step of a drag). All log on transitions, never per frame; their catalog descriptions mention the Output panel.8. Validation
77899e8d9(A + B fixes)ed91212c4702582560ed91212c4(typecheck, lint, sync, unit, webgl, webgpu, audio, tilemap, bench, site, smoke)release-distlocally with a production buildtest/site,test/ci,test/release,test/examples, demo-assets loadingdemo-panel.test.tschannel-artifact verify3b26123e03b26123e0pnpm test:playground:e2e, new, runs in the CI smoke job)preview-console.test.ts(18), alias routes, audio unlock regression, sidecar format;test/siteslice 157,test/audio663, demo-assets 175docs:api:check,examples:sync:check) and site: PASS;browser-audio-chromium38/38verify:package-policy,verify:publish,verify:external-consumers,verify:release-matrix,size,release:prepareincl. full ZIP9. Open limitations
/ExoJS/and/ExoJS/next/(W16) need separate approval; real GitHub API candidate selection runs only in the publisher.demoAssetscopies the whole standard set and breaks relative references of maps and bitmap fonts; documented, not redesigned.src/debug/index.tsre-export ofPhysicsDebugDrawwith an internal base module.View.screenToWorld(x, y)divides byview.width, whichsetZoomchanges, so it maps wrongly at any zoom other than 1 (the world-vs-screen-coords readout drifts when zoomed). The Asset Browser uses the four-argument form. Worth a separate fix with a decision on the documented contract.