Repository navigation
SceneScript Runtime
Deepratna Awale edited this page Oct 6, 2026
·
5 revisions
SceneScript is Wallpaper Engine's JavaScript API for scenes. Open Wallpaper Engine runs it on JavaScriptCore, one runtime per wallpaper instance, on its own thread. The evidence and plan, including the specification assembled from WE's own type declarations and documentation, are in docs/scenescript-plan.md.
| Piece | Role |
|---|---|
SceneScriptRuntime (Runtime/) |
One JSVirtualMachine and JSContext per instance, WE's prelude, every script of the scene as a record in runtime.js, and the load and frame drivers |
SceneScriptThread |
A serial queue off the main thread; a script that hangs until the watchdog fires stalls only its wallpaper's scripts, never the UI |
SceneScriptWallpaper (Host/) |
Ties a runtime and its extensions to the renderer that owns it |
Object table (Objects/, Host/SceneScriptTableSync) |
Layer, effect and material objects; the renderer writes each object's drawn values before the frame and draws what scripts wrote after it |
Modules/ |
A tokenizer and module transformer that turns WE's ES modules into records the runtime loads |
| Extensions |
Engine/ (engine, input, console, localStorage), Audio/ (registerAudioBuffers), Cursor/ (events and hit testing), Media/ (Now Playing), Binding/ (script properties and user properties) |
JavaScript-side code lives in bundled .js resources, not Swift strings.
- The renderer calls
submit(_:)at the start of each draw with the frame's inputs (time, cursor, audio, properties). - The scripts run on their thread (
asyncFrame) and leave aSceneScriptFrameState. - The renderer waits briefly for it, so what scripts did is drawn in the same frame, as in WE. A slow script drops script frames, not render frames.
- WE's lifecycle:
init(),update(value)every frame,destroy,applyUserProperties(changed keys only),resizeScreen, themedia*callbacks,animationEvent. - WE's object model:
thisScene,thisLayer,engine,input, layers, effects (getEffect(...).visible), materials (getMaterial,setMaterialProperty), animations (getAnimation,getTextureAnimation). -
createLayerfrom an asset (image, text, shape, particle system, sound),destroyLayer,sortLayer,getLayerIndex. - Sound layers under script control;
localStorage; timers. - Cursor events (
cursorMove,cursorDown,cursorUp,cursorClick,cursorEnter,cursorLeave) on solid layers with hit testing, in scene space; clicks count only on the wallpaper. - Live left/right
registerAudioBuffers(16/32/64 bands). - Now Playing, including on macOS 15.4+ through a small adapter (see Audio system).
- WE's JS modules and classes (
WEMath,WEVector,WEColor, Vec/Mat) from the assets. - Puppet and model posing through the animation-layer and bone APIs.
- Return values converted as WE converts them (vectors, numbers, strings, flags).
- The
com.apple.security.cs.allow-jitentitlement lets JavaScriptCore JIT-compile scripts. - No per-frame closures or intermediate arrays per bound script; material writes that change nothing send no command; strings are flushed only when they changed.
- Script exceptions are deduplicated and logged with repeat counts.
-
SceneScriptLibraryCostTestsreports each library script's cost (OWE_SCRIPT_COST_REPORT);SceneScriptCorpusReplayTestsreplays every library script (OWE_REPLAY_REPORT).
- Animation layers and bones are complete with models and puppets; WP12's remaining items are tracked in the plan.
- A particle rate bound to a script can cost 0.5–4 ms a frame in the script engine.
User guide: Scene wallpapers
Open Wallpaper Engine · GPL-3.0 · Released by Deepratna Awale · Based on Open Wallpaper Engine by Haren Chen and MrWindDog · Not affiliated with Wallpaper Engine or Valve · Home · User Guide · Developer Guide