webwallgl 1.3.16 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +17 -103
- package/README.md +17 -103
- package/package.json +1 -1
- package/types.d.ts +41 -2
- package/webwallgl.d.ts +15 -0
- package/webwallgl.global.js +6267 -1024
- package/webwallgl.global.js.map +1 -1
- package/webwallgl.global.min.js +211 -74
- package/webwallgl.global.min.js.map +1 -1
- package/webwallgl.min.mjs +211 -74
- package/webwallgl.min.mjs.map +1 -1
- package/webwallgl.mjs +6267 -1025
- package/webwallgl.mjs.map +1 -1
package/README.en.md
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
## Introduction
|
|
6
6
|
|
|
7
|
-
WebWallGL is a browser-side renderer for Wallpaper Engine wallpapers — scene, video, and web: its main job is replaying workshop scene packages (scene.pkg) in WebGL in real time, with layer effect chains, particles, 3D puppet bones, text widgets, script sandboxes, audio response and live user-property updates; web wallpapers run in a sandboxed iframe with a WE API shim injected before author scripts. Upcoming versions will add effects exclusive to this library — stay tuned.
|
|
7
|
+
Make Wallpaper Engine great again!!! Congratulations — you've found a treasure. This is the most faithful, most feature-complete, and fastest-updated self-built Wallpaper Engine core on the web, implemented in pure TypeScript/JS. WebWallGL is a browser-side renderer for Wallpaper Engine wallpapers — scene, video, and web: its main job is replaying workshop scene packages (scene.pkg) in WebGL in real time, with layer effect chains, particles, 3D puppet bones, text widgets, script sandboxes, audio response and live user-property updates; web wallpapers run in a sandboxed iframe with a WE API shim injected before author scripts. Upcoming versions will add effects exclusive to this library — stay tuned. If your project uses this library, please give it a star — many thanks!
|
|
8
8
|
|
|
9
9
|
- [GitHub repository](https://github.com/oneincase/webwallgl)
|
|
10
10
|
- [Live demo (GitHub Pages)](https://oneincase.github.io/webwallgl/)
|
|
11
11
|
|
|
12
|
-
- Zero runtime dependencies, single-file delivery (min ESM ~
|
|
12
|
+
- Zero runtime dependencies, single-file delivery (min ESM ~930KB / gzip ~295KB)
|
|
13
13
|
- Installable via npm or a <script> CDN tag; multiple isolated instances per page
|
|
14
14
|
- This bench is the library's first consumer — everything you see here is public API
|
|
15
15
|
|
|
@@ -36,12 +36,12 @@ import { mount, httpSource } from "webwallgl";
|
|
|
36
36
|
|
|
37
37
|
```
|
|
38
38
|
// 2) ESM CDN via jsDelivr (without a bundler)
|
|
39
|
-
import { mount, httpSource } from "https://cdn.jsdelivr.net/npm/webwallgl@1.
|
|
39
|
+
import { mount, httpSource } from "https://cdn.jsdelivr.net/npm/webwallgl@1.4.1/webwallgl.min.mjs";
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
```
|
|
43
43
|
<!-- 3) UMD <script>: exposes the global WebWallGL -->
|
|
44
|
-
<script src="https://cdn.jsdelivr.net/npm/webwallgl@1.
|
|
44
|
+
<script src="https://cdn.jsdelivr.net/npm/webwallgl@1.4.1/webwallgl.global.min.js"></script>
|
|
45
45
|
<script>
|
|
46
46
|
const { mount, httpSource } = WebWallGL;
|
|
47
47
|
</script>
|
|
@@ -101,7 +101,6 @@ The library makes only two network requests (scene.pkg and optional project.json
|
|
|
101
101
|
|
|
102
102
|
| Factory | Use case |
|
|
103
103
|
| --- | --- |
|
|
104
|
-
| `1.3.16` | 2026-09-11 | Media-component fixes and branding: (1) album covers on 33 wallpapers rendered as black placeholders because the $mediaThumbnail / $mediaPreviousThumbnail binding in an effect pass usertextures slot was dropped by parsing; the binding is now merged so covers show. (2) media title/artist layers were blank because width-limited wrapping was squeezed by the 2x2 placeholder box; the text canvas now grows only for placeholder-sized boxes, and typewriter scripts no longer stick at the placeholder text. (3) simulated audio is now true stereo. (4) the simulated media source is rebranded: title WebWallGL, artist oneincase, cover is the library logo. (5) fix lost font after the shared text canvas is resized: assigning textCanvas.width/height resets the 2D context and wipes the font back to the default 10px, so large clocks/dates were nearly invisible (2468489223, 3379996991); drawing now uses an explicit font string. (6) fix clock/date scripts misclassified as writeback and having their text cleared (3379996991). |
|
|
105
104
|
| `httpSource(baseUrl, init?)` | HTTP base URL; falls back through the three real layouts: scene.pkg → scenes/scene.pkg → gifscene.pkg |
|
|
106
105
|
| `fileSource(file, project?)` | A local .pkg from <input type=file> or drag & drop |
|
|
107
106
|
| `bytesSource(pkg, project?, key?)` | Bytes already in hand (bundled, IndexedDB cache, custom transport) |
|
|
@@ -124,15 +123,24 @@ input.addEventListener("change", () => {
|
|
|
124
123
|
| --- | --- | --- |
|
|
125
124
|
| `source (required)` | `—` | See Source above |
|
|
126
125
|
| `fit` | `"cover"` | cover crops to fill / contain letterboxes / stretch distorts |
|
|
127
|
-
| `renderDpr` | `
|
|
126
|
+
| `renderDpr` | `0 (auto)` | Render DPR: 0 = follow devicePixelRatio (native-sharp on Retina/HiDPI); a positive number = target DPR and may exceed the reported device value (supersamples to physical resolution even when a host WKWebView misreports 1). Physical long edge capped at 4096; lower it to save VRAM. The tier also drives the texture resource scale — at lower tiers textures resolve to smaller sizes per layer footprint (see "VRAM & clarity" below) |
|
|
128
127
|
| `fps` | `60` | FPS cap; skipped frames don't count into stats.fps, so drops are visible |
|
|
129
128
|
| `volume` | `0` | 0..1. Starts muted (autoplay policy); set a non-zero volume after ready |
|
|
130
129
|
| `autoplay` | `true` | When false, stays paused after mount |
|
|
131
130
|
| `properties` | `{}` | Initial user property overrides (keys are property names) |
|
|
132
131
|
| `pointer / audio / media` | `built-in` | Pointer follows the canvas; audio/media are deterministic sims; pass null to disable |
|
|
133
132
|
| `features` | `all on` | Debug switches: models / text / particles / effects / components |
|
|
133
|
+
| `quality` | `all defaults` | Render quality tiers (like the WE client's performance options): antiAliasing "off" (default)/"fxaa"/"msaa2"/"msaa4", particles "high" (default)/"medium"/"low"/"off" (low/medium scale both the count cap and emission rate), postProcessing "high" (default)/"medium"/"low"/"off" (low/medium cap effect-chain FBO resolution; off bypasses effect chains, fullscreen post layers and Bloom). Supersampling lives in renderDpr |
|
|
134
134
|
| `onReady / onError / onDiagnostic` | `—` | Callback surface; can also subscribe later via instance.on() |
|
|
135
135
|
|
|
136
|
+
VRAM & clarity: textures plus canvas/effect-chain buffers dominate VRAM, and both scale automatically with the mount options — no manual management required:
|
|
137
|
+
|
|
138
|
+
- Textures auto-pick their resolution from "clarity × the layer's on-screen footprint": as long as texture resolution ≥ the layer's device-pixel footprint, output is pixel-identical to full-resolution assets — only oversampling is removed. Mip-chained textures just truncate the chain (zero resampling); single-image giants get resampled
|
|
139
|
+
- Compressed textures (DXT1/3/5, BC7, ETC2) upload their embedded mip chains straight to the GPU instead of decoding to RGBA; single-channel R8 uploads as GL_R8. Unsupported browsers fall back to the decode path with identical visuals
|
|
140
|
+
- CPU-side decoded copies are freed right after upload (except multi-frame animated .tex) — up to hundreds of MB on the worst wallpapers
|
|
141
|
+
- Whitelisted assets never shrink: LUT data grids, multi-frame animations and video textures stay native; normal/mask maps have their own floor. window.__memStats() after mount reports per-bucket usage (package/decoded/uploaded)
|
|
142
|
+
- Recommended combo for low-memory devices: clarity 0.8 + quality low (particles/post low, anti-aliasing off). On 4K screens the canvas and effect-chain FBOs dominate — they grow with DPR squared and MSAA4 multiplies by 4 — textures come second
|
|
143
|
+
|
|
136
144
|
## The SceneInstance API
|
|
137
145
|
|
|
138
146
|
| Member | Description |
|
|
@@ -140,6 +148,7 @@ input.addEventListener("change", () => {
|
|
|
140
148
|
| `pause() / resume() / paused` | Pause/resume. Never remounts the package: video/audio resume from where they were |
|
|
141
149
|
| `setFit(fit) / setFps(n) / setVolume(v)` | Live updates, no remount (the render loop reads them per frame) |
|
|
142
150
|
| `setRenderDpr(dpr)` | Changing DPR rebuilds the canvas; remounts internally (pkg cache hit, no re-download) |
|
|
151
|
+
| `setQuality(patch) / getQuality()` | Live quality-tier patch (partial update), applied in place with no remount; survives scene/load() changes |
|
|
143
152
|
| `setProperties(props)` | Live property updates: patches the property table / effect constants / script sandboxes in place, no re-fetch |
|
|
144
153
|
| `getProperties()` | The current flattened property value map |
|
|
145
154
|
| `setAudio(src)` | Swap the audio spectrum source (pull model, once per frame); null falls back to the built-in sim. Survives scene changes. Works for scene and web |
|
|
@@ -245,7 +254,7 @@ console.log(wp.media.snapshot.title);
|
|
|
245
254
|
wp.media.playPause();
|
|
246
255
|
```
|
|
247
256
|
|
|
248
|
-
- The five palette fields must be chainable color objects (scripts write c.subtract(o).multiply(t).add(o); a plain array throws a TypeError that kills the whole script) — createMediaSource guarantees this for you
|
|
257
|
+
- The five palette fields must be chainable color objects (scripts write c.subtract(o).multiply(t).add(o); a plain array throws a TypeError that kills the whole script) — createMediaSource guarantees this for you; to build one by hand use the exported mediaColor(r, g, b), which accepts 0..1 components, {x,y,z} or arrays and returns an object with the full chain API
|
|
249
258
|
- All transport methods are optional: if you only provide metadata, wallpaper buttons are silently inert rather than throwing
|
|
250
259
|
- setMedia survives scene changes: install once and it applies to every scene loaded afterwards
|
|
251
260
|
- For video wallpapers the audio spectrum is captured from the <video> automatically (visualizers react to the video's own audio); an explicit setAudio() injection takes precedence
|
|
@@ -329,102 +338,7 @@ b.pause(); // does not affect a
|
|
|
329
338
|
|
|
330
339
|
## Changelog
|
|
331
340
|
|
|
332
|
-
Current version: 1.
|
|
333
|
-
|
|
334
|
-
| Version | Date | Notes |
|
|
335
|
-
| --- | --- | --- |
|
|
336
|
-
| `1.3.15` | 2026-09-08 | The video pair gains a self-healing watchdog: elements can enter "phantom playback" (paused=false but the decoder stalls and time stops advancing, with no event to listen for), freezing the wallpaper permanently — the render loop now detects currentTime not advancing for ~500ms on a visible page and hard-restarts decode via pause→play; legitimate throttling while the page is occluded is not misjudged |
|
|
337
|
-
| `1.3.14` | 2026-09-08 | Fourth pass at loop handover: the hard cut became a fast fade. Crawling keeps the layer beneath already moving while the old main (holding its last frame) fades out linearly over 64ms — the blend window masks the 1–3 frames of imprecision inherent to element-level handover (ended dispatch, layer-swap compositing) instead of requiring every stage to be zero-latency |
|
|
338
|
-
| `1.3.13` | 2026-09-08 | Third pass at seamless-loop handover, "crawling": during the main video's final 0.12s the standby actually plays at 1/8 rate (its pipeline stays in the playing state while advancing only ~1 frame); on ended the rate flips back to 1x and layers swap in the same tick — a rate change is a pure clock operation, removing both the wakeup/freeze and the content jump of earlier versions |
|
|
339
|
-
| `1.3.12` | 2026-09-08 | Loop handover refined again: pre-play removed (it caused a transient dual-4K-decode contention plus a content jump at the swap); the main video now holds its last frame on ended while the standby is started and confirmed to actually advance before layers swap — the hold lands on the content cut, reading as a normal edit |
|
|
340
|
-
| `1.3.11` | 2026-09-08 | Seamless-loop handover reworked to "pre-play + exact ended swap": the standby actually starts playing underneath the main video a few frames before the end, and layers swap the instant ended fires (frame-exact, not polled) — eliminating the resume-wakeup latency and rAF detection lag behind the last 1–2 frame hitch |
|
|
341
|
-
| `1.3.10` | 2026-09-08 | destroy() gains a releasePkgCache option: destroying an instance also evicts that wallpaper's parsed scene.pkg cache (previously the old package stayed cached after switching, so memory never dropped) |
|
|
342
|
-
| `1.3.9` | 2026-09-08 | New pushWheel channel for wheel / macOS trackpad injection (web wallpapers only): synthesizes wheel plus the legacy mousewheel, and maps a two-finger pinch to ctrl+wheel; pushPointer gains an optional modifier mask |
|
|
343
|
-
| `1.3.8` | 2026-09-08 | Video wallpapers now render as DOM video: 4K is no longer downsampled to 2048 (sharpness) and an A/B element pair gives seamless looping (loop-point hitch 84ms→33ms); the in-scene video texture cap now follows the render target too |
|
|
344
|
-
| `1.3.7` | 2026-09-08 | Fix: the library entry's setRenderDpr / restore remount went fully black (it reused a canvas whose context had been lost); scene wallpapers now support the real cover texture via $mediaThumbnail |
|
|
345
|
-
| `1.3.6` | 2026-09-08 | New MediaSnapshot.thumbnail: the host can now pass the real album cover to web wallpapers (previously only colors were available, and the cover was always a gradient placeholder) |
|
|
346
|
-
| `1.3.5` | 2026-09-08 | xray effect: when the author doesn't configure size in the scene, the fallback is now 1 (identity) instead of the shader comment's 0.2 |
|
|
347
|
-
| `1.3.4` | 2026-09-08 | Closes the four items deferred from 1.3.3: setFit now affects web wallpapers, audio:null truly mutes, the bare-iframe fallback no longer reports 0 fps, and debug globals are cleared on unmount |
|
|
348
|
-
| `1.3.3` | 2026-09-08 | Full audit: fixed autoplay:false hanging mount(), setMedia being inert on the scene path, AudioContext leaking on wallpaper swap, and more |
|
|
349
|
-
| `1.3.2` | 2026-09-08 | Fix: the "live system" microphone only fed scene wallpapers; web wallpaper visualizers still showed the synthetic stream |
|
|
350
|
-
| `1.3.1` | 2026-09-08 | Fix: injected audio/media sources never reached web wallpapers (visualizers kept playing the default stream) |
|
|
351
|
-
| `1.3.0` | 2026-09-08 | mediaSource() for arbitrary video/images; type sniffing; volume for media wallpapers; one Now Playing driver shared by scene and web |
|
|
352
|
-
| `1.2.0` | 2026-09-08 | Video wallpapers work through the library entry; audio and pointer injection wired into the public API (three downstream reports) |
|
|
353
|
-
| `1.1.0` | 2026-09-07 | External pointer injection channel, web wallpaper interaction, effect-pass compile fixes, complete pause semantics |
|
|
354
|
-
| `1.0.0` | 2026-09-06 | First stable release: the public API is settled (mount / SceneInstance / Source) |
|
|
355
|
-
| `1.0.0-beta1` | 2026-09-04 | First public preview |
|
|
356
|
-
|
|
357
|
-
1.3.9 adds a wheel-injection channel. Pointer injection (pushPointer) always carried only position and buttons, never the wheel — the desktop wallpaper window receives no mouse events, and so no wheel either. But scanning all 256 local wallpapers showed a narrower scope than expected: the 194 scene wallpapers have zero wheel consumers (the WE scene script sandbox has no wheel API at all; every scroll token in a scene package is the texture-scroll layer effect g_ScrollSpeed), so only web wallpapers matter. Of the 52 web wallpapers, exactly one genuinely consumes the wheel — a 360° panorama (3406740580, where the wheel changes the field of view) — plus one wallpaper where three.js OrbitControls has zoom enabled by default. The snag is that the panorama listens only to the legacy mousewheel / DOMMouseScroll, never the modern wheel, while OrbitControls listens only to the modern wheel — synthesizing either one alone leaves the other class completely inert, with no error. So the web side now dispatches both a modern wheel and a legacy mousewheel per push (wheelDelta has the opposite sign to deltaY and detail stays 0); DOMMouseScroll is deliberately not dispatched, because each of the three legacy consumers binds it and mousewheel to the very same handler, so firing all three would process one scroll twice — the FOV jumps two steps at a time and merely looks like an over-sensitive wheel. macOS trackpad support is the point: two-finger scroll is a plain pixel wheel (deltaMode=0), while a two-finger pinch is translated, exactly as browsers do, to a wheel whose ctrl bit is set (OrbitControls / pano2vr rely on event.ctrlKey to tell zoom from scroll); when mapping from NSEvent.magnify the host must negate scrollingDeltaY. Wheel position reuses the last pointer coordinates. Calling pushWheel for a scene wallpaper is silently inert, the same treatment as video and other media wallpapers.
|
|
358
|
-
|
|
359
|
-
1.3.8 is a set of video-wallpaper changes, prompted by 4K video looking soft. The cause was not any sharpness setting: video frames used to be uploaded as WebGL textures, and that path had a hard-coded 2048 long-edge cap — a 3840×2160 source became 2048×1152 (28% of the area) and was then scaled back up to fill the screen, while a Retina render target is commonly 3024 or even 3840. In effect you were shown an upscaled 2K image. Video wallpapers now display through a plain `<video>` element instead: the browser decodes and composites in hardware at display size, so you get native resolution, and a WebGL context plus a full-canvas upload per frame are saved. The trade-off is that pure video wallpapers lose effect-chain/particle overlay — which they never used anyway. Wallpapers with an in-scene video texture layer don't take this path, but that path's cap was also changed to min(hardware MAX_TEXTURE_SIZE, render-target long edge, 3840): uploading a texture larger than the render target is pure waste, as the extra pixels are discarded at sampling time.
|
|
360
|
-
|
|
361
|
-
The same version also wires up seamless looping. WebKit's `<video loop>` resets the decode pipeline at the loop point and no amount of buffering avoids it — measured on a 12-second 3840×2160@60fps clip, the worst frame gap at the loop point was 84ms (roughly five dropped frames). The library already had an A/B element scheme (as the main element nears the end, the standby starts, plays one or two frames and pauses to stay warm, then hands over within 2–5 frames of the true end); it just wasn't wired to video wallpapers, and the DOM path's comment claimed "dropped the pair, halves memory". Measurement shows that claim was wrong: the standby element has **no src** most of the time and only preheats in the final 0.5s window, so on a 12-second clip the overlap is under 5% — process RSS peak went from 128MB to 130MB while the worst loop-point gap dropped to 33ms. So it is on by default with no switch. If the standby isn't ready in time it falls back to native loop, which merely restores the old behaviour rather than interrupting or blanking. Also fixed along the way: `pause`/`resume`/`setVolume`/`setFit` previously only knew about scene instances and silently did nothing for DOM video; not reporting a first frame on the DOM path left `mount()`'s promise hanging forever; and without continuous frame marking `instance.stats` always reported "stopped". Liveness deliberately uses rAF rather than requestVideoFrameCallback — the latter exists but never fires in WKWebView (0 callbacks in 1.5s while the video plays normally).
|
|
362
|
-
|
|
363
|
-
1.3.7 has two items, both on the unmount-then-remount path. First, the library entry's setRenderDpr and restore went fully black after remounting: teardown calls renderer.dispose(), which uses WEBGL_lose_context.loseContext(), and per spec a subsequent getContext("webgl2") on that same canvas returns the very same lost context object (verified: identical reference, isContextLost() true) — only a fresh canvas yields a usable context. The full-page renderer never hit this because its teardown clears the container's innerHTML and the canvas goes with it; the library form has no such container, so the canvas was kept and reused, and a host merely changing the resolution got a black screen with no error at all, since neither method arms a first-frame guard. Now the context's liveness is checked before reuse and a dead canvas is replaced; when the caller passed its own canvas (the library must not swap someone else's DOM) an explicit error is reported instead. Second, scene wallpaper covers: unlike web wallpapers these don't go through a script callback — authors put the reserved WE texture names $mediaThumbnail / $mediaPreviousThumbnail straight into a layer's image / textures slot, so the MediaSnapshot.thumbnail added in 1.3.6 meant nothing to the scene path. A cover change in the snapshot is now decoded asynchronously and uploaded as a GL texture (the previous one shifts to $mediaPreviousThumbnail), sharing the same pixel-upload code as the existing "live system" path.
|
|
364
|
-
|
|
365
|
-
1.3.6 contains a single change: the missing cover channel in the media snapshot. MediaSnapshot previously carried only hasThumbnail plus the five color fields, with no image data — the event.thumbnail delivered to a web wallpaper's mediaThumbnailChanged was a 64×64 gradient the library painted from primary/secondary, so corpus code like `img.src = e.thumbnail` ran but never showed a real cover. MediaSnapshot and createMediaSource now both take an optional thumbnail (data URL or same-origin URL): when the host supplies it, it is passed through verbatim; when it doesn't, the gradient placeholder is still used. Supplying thumbnail without hasThumbnail implies the latter. The event diff also accounts for thumbnail now — system media interfaces typically deliver the track name first and the artwork a moment later, so watching only hasThumbnail/trackIndex would miss the "same track, cover just arrived" transition. Scene (WebGL) wallpapers can't use it in this version: their scripts read only hasThumbnail and the colors, and the image itself travels through a reserved texture (see 1.3.7).
|
|
366
|
-
|
|
367
|
-
1.3.5 contains a single change: the xray effect's fallback value. xray's size drives the effect radius (it is inverted internally, so size=1 is identity). When the author doesn't write size into the scene's constantshadervalues, the shader declaration comment's "default":0.2 used to be applied — but that is the slider's initial position when the WE editor creates the effect, not a runtime fallback: as soon as the editor attaches the effect to a layer it writes the current slider value into the scene file, so the official runtime always reads an explicit value. Applying 0.2 shrank the effect radius to a fifth, leaving only a small patch around the cursor. The fallback is now 1. The change is scoped to this one parameter; the comment defaults for multiply and the texture slots are unchanged.
|
|
368
|
-
|
|
369
|
-
1.3.4 closes the four items 1.3.3 listed as deferred. All four are observable behaviour bugs, not cleanup refactors:
|
|
370
|
-
|
|
371
|
-
- **setFit() did nothing on web wallpapers**: it only updated the config and the cover alignment, while a web wallpaper's scaling lives in an iframe transform written by a layout pass. Without a re-layout the old ratio stayed. setFit now triggers one (scene and media wallpapers read the config every frame and were never affected)
|
|
372
|
-
- **The bare-iframe fallback reported 0 fps forever**: when shim injection fails that path starts no rAF at all, so nothing advanced the frame counter and hosts saw what looked like a dead wallpaper. The fallback now runs a heartbeat rAF and reports the real refresh rate
|
|
373
|
-
- **audio:null fell back to the synthetic stream on web wallpapers instead of muting**: the check only asked whether an injected source existed, conflating "explicitly disabled" with "never set". The two are now distinct, and audio:null / media:null genuinely disable on both scene and web (setAudio(src) re-enables)
|
|
374
|
-
- **Debug globals outlived unmount**: 19 diagnostic hooks such as __scene and __textures stayed on window after clear(), pointing at the destroyed scene's object graph. That both pinned the previous wallpaper's textures and layer tree in memory and let hosts read stale state from the console. clear() now deletes each of them
|
|
375
|
-
|
|
376
|
-
1.3.3 is a full audit covering unwired API, defects and memory leaks. Everything fixed here was confirmed by measurement:
|
|
377
|
-
|
|
378
|
-
- **autoplay:false hung mount() forever** (scene and media wallpapers): pausing before assembly meant the render loop never ran a single frame, so the only first-frame trigger was unreachable and the promise neither resolved nor rejected. Measured: the same wallpaper resolved by default but was still pending after 500 live rAF frames with autoplay:false. It now assembles normally and pauses after the first frame is drawn
|
|
379
|
-
- The first-frame callback now fires after render() completes (previously it ran before the render call, landing one frame early, so autoplay:false handed back a blank canvas)
|
|
380
|
-
- **setMedia() was inert on scene wallpapers**: the scene captured its media driver once at assembly, while setMedia is typically called after mount(). It now re-picks on every read (the web path already did)
|
|
381
|
-
- **Swapping wallpapers leaked an AudioContext**: the video spectrum takeover registered its release on the instance-level list, but swapping goes through clear() while only destroy() drained it. Browsers cap out at roughly 6 AudioContexts, after which audio reactivity silently dies. A per-wallpaper release list is now drained by clear()
|
|
382
|
-
- **One throwing cleanup dropped the entire teardown**: clear() called the assembly-layer cleanup without try/catch, so a single exception skipped the WebGL context release, video element recycling and blob revocation that followed
|
|
383
|
-
- **Swapping wallpapers during the mic permission prompt orphaned the stream**: getUserMedia blocks on the system dialog, and the release was registered after the await, so nothing on that path ever called it and the browser's recording indicator stayed lit. Both assembly paths now register the release slot synchronously
|
|
384
|
-
- The instance.media control surface is reset by clear() (previously it still pointed at the destroyed scene's sandbox closures after release()/destroy())
|
|
385
|
-
|
|
386
|
-
Still unwired by design (marked in the type comments): MountOptions' pointer and features. Use pushPointer() to feed pointer state from outside.
|
|
387
|
-
|
|
388
|
-
1.3.2 closes the **second channel** of the same symptom: 1.3.1 fixed host injection (setAudio), while the bench's "live system" checkbox takes a different path (cfg.liveSystem, where the library captures the microphone itself). That path was only consumed by the scene assembly — web.ts referenced liveSystem zero times — so ticking the box made scene visualizers follow the mic while web wallpapers stayed on the synthetic stream.
|
|
389
|
-
|
|
390
|
-
- Web wallpapers now receive the live-system microphone through the same capture path as scene (startLiveSystem)
|
|
391
|
-
- Microphone capture is asynchronous (getUserMedia needs user consent) and does not block pump startup: the default source runs first, then the mic is filled in and the per-frame source pick switches over
|
|
392
|
-
- Audio source priority: host injection (setAudio) > live-system microphone > built-in simulation
|
|
393
|
-
- The microphone stream is released on teardown (otherwise the browser's recording indicator stays lit)
|
|
394
|
-
|
|
395
|
-
1.3.1 fixes a defect found downstream in real use: **the microphone was connected, yet web wallpapers kept showing the default synthetic stream**.
|
|
396
|
-
|
|
397
|
-
- Root cause 1: the web assembly path never read rt.audioBridge (1.3.0 wired this up for the media source but missed the audio line), so injected spectra never reached the iframe
|
|
398
|
-
- Root cause 2: both the audio and media pumps captured their driver at assembly time, while setAudio()/setMedia() are typically called after mount() (that is when the host's microphone or SSE channel becomes ready) — a fixed driver means a later source never takes effect. Both pumps now pick their source per frame and fall back cleanly when the source is removed
|
|
399
|
-
- Injected spectra are no longer put through the gamma contrast expansion: that step exists for the built-in simulation's unclamped bands, and applying it to a host's already-normalized 0..1 spectrum would peg every bar at full scale
|
|
400
|
-
|
|
401
|
-
1.3.0 continues directly from 1.2.0, closing four more items reported by the downstream host:
|
|
402
|
-
|
|
403
|
-
- New mediaSource(urlOrFile): any video or image can be a wallpaper, from a remote URL or a local File (drag & drop). The library revokes the objectURL on destroy()/source swap — without that, every wallpaper change would leak a multi-megabyte blob
|
|
404
|
-
- Type sniffing: with no project.type the URL extension decides (correctly stripping a signed URL's ?query and #hash), falling back to scene only when unrecognized. An explicit project.type always wins and is never overridden
|
|
405
|
-
- setVolume now works on media wallpapers (previously a complete no-op — volume only reached the scene audio graph). It writes both volume and muted, since changing volume on a muted <video> does nothing; if unmuting is blocked by the autoplay policy that is reported via onDiagnostic rather than silently swallowed
|
|
406
|
-
- MediaSource was widened to the driver's real contract (an 18-field snapshot plus five optional transport methods) and is now **one shared instance across scene and web** — previously each side created its own simulation with no way for the host to inject. The new createMediaSource() takes only the fields you have and fills in palette, lyric line and trackIndex, guaranteeing chainable color instances
|
|
407
|
-
- New SceneInstance.setMedia() and a media control surface (snapshot plus previous/next/play-pause); transport commands forward straight to the host driver, and host-side data updates are visible to the engine in the same frame
|
|
408
|
-
- Video wallpapers capture their spectrum from the <video> itself so visualizers react to the video's own audio; an explicit setAudio() injection takes precedence
|
|
409
|
-
|
|
410
|
-
1.2.0 closes three gaps where the runtime capability already worked but was never exposed through the library entry (reported by the downstream host wallpaperEM):
|
|
411
|
-
|
|
412
|
-
- video / gif / image wallpapers can now be mounted via mount(): a new Source.mediaEntry() supplies the URL and the media path gained the library contract it lacked. Previously it fired neither onFirstFrame nor onError, so even with routing in place the mount() promise would hang forever — never resolving, never rejecting
|
|
413
|
-
- The media path now honors a caller-supplied canvas and sizes its backing store from CSS dimensions rather than the window (previously an embedded canvas got a full-window buffer and was never inserted into the DOM at all)
|
|
414
|
-
- MountOptions.audio is actually wired now (it was a declared-but-unreferenced dead field), plus a new SceneInstance.setAudio() for swapping after mount — host spectrum channels usually become ready only after mount()
|
|
415
|
-
- New SceneInstance.pushPointer() / pointerLeave(), matching the full-page renderer's __wp in both name and signature so downstream code needs no changes when migrating to the library
|
|
416
|
-
- Known boundaries at the time: audio injection was scene-only — web wallpapers use a separate iframe-shim channel, wired up in 1.3.1; media wallpapers have no pointer concept; MountOptions' pointer / media / features were unwired (media landed in 1.3.0)
|
|
417
|
-
|
|
418
|
-
What went into 1.1.0 (merged after 1.0.0):
|
|
419
|
-
|
|
420
|
-
- New external pointer injection channel (__wp.pushPointer / pointerLeave): when the wallpaper window cannot receive the mouse (e.g. the Finder desktop window swallows events on macOS), the host polls the system cursor and pushes it in. Scene and web wallpapers share one protocol — callers need not branch on type
|
|
421
|
-
- Web wallpapers joined the same channel: the shim synthesizes DOM events against the hit element (full over/out/enter/leave chains, click derived from button edges). Of 49 local web wallpapers, interaction went from dead to working on 24 with mousemove, 29 with click and 16 with pointer events. Hard limit: CSS :hover is driven by browser hit-testing and cannot be lit by synthetic events
|
|
422
|
-
- Effect-pass compile failures driven to near zero (seven rounds): the transpiler now handles int/float mixing, macro scoping, vector narrowing, scientific notation and more. Library-wide effect-pass compilation went from 1653/1873 (88.3%) to 1823/1873 (97.3%), +170 in total. The symptom was an effect silently missing — a failed compile only warns, so god rays / visualizers / glows simply vanished
|
|
423
|
-
- Pause semantics completed: pausing must freeze rAF/timers and CSS animations together (compositor-driven CSS animations ignore JS freezing — 1444432396 kept animating after pause); resuming must re-arm held rAF callbacks (self-recursive rAF wallpapers break their chain permanently — 1278092907 froze forever after resume), restoring only what we paused
|
|
424
|
-
- Fidelity fixes: keyframe animations now run on the real clock (previously they accumulated the target frame interval, diverging from the bone clock by 5.5s over 30s — hair desynced from the head and the scalp showed through); object scripts and keyframe animations now work in local space with per-frame parent/child recomposition (previously local return values were written straight into world slots, so elements drifted away untouched and got clipped); hidden mask layers referenced by clipping_mask now correctly read back what is behind them (previously they fell back to the referencing layer itself, painting a solid white block)
|
|
425
|
-
- Two new documentation sections, "Mount target" and "User properties": web wallpapers require a container div rather than a canvas, and what value shape each property type expects
|
|
426
|
-
|
|
427
|
-
The full commit history lives in the GitHub repository; every fix records its symptom, root cause, measured scope and verification method in the commit message.
|
|
341
|
+
Current version: 1.4.1. Per-version lists are no longer maintained here: every change records its symptom, root cause, measured scope and verification method in the corresponding commit message — see the commit history and Releases on the GitHub repository.
|
|
428
342
|
|
|
429
343
|
## Copyright & compliance
|
|
430
344
|
|
package/README.md
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
## 简介
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
让 Wallpaper Engine 实现再次伟大!!!恭喜你发现宝藏,这是全网复刻程度最高,功能最强,更新最快的 Wallpaper Engine 自研核心库,纯 TypeScript/JS 实现。webwallgl 是一个浏览器端的 Wallpaper Engine「scene」场景、视频、web 网页壁纸渲染库:主要功能是把创意工坊场景包(scene.pkg)在 WebGL 里实时还原,支持图层效果链、粒子、3D 木偶骨骼、文字挂件、脚本沙箱、音频响应与用户自定义属性热更新;网页类型壁纸经 sandbox iframe + 加载前 WE shim 注入运行。后续版本将加入本库独有效果支持,请敬请期待。下游如果进行了库的引用,麻烦给个 star,非常感谢!
|
|
8
8
|
|
|
9
9
|
- [GitHub 开源仓库](https://github.com/oneincase/webwallgl)
|
|
10
10
|
- [在线版(GitHub Pages)](https://oneincase.github.io/webwallgl/)
|
|
11
11
|
|
|
12
|
-
- 零运行时依赖,单文件引入(min ESM 约
|
|
12
|
+
- 零运行时依赖,单文件引入(min ESM 约 930KB / gzip 约 295KB)
|
|
13
13
|
- 可 npm 安装,也可 <script> CDN 引入;一页可开多个互不干扰的实例
|
|
14
14
|
- 本测试台本身就是库的第一个使用者 —— 你在这里看到的能力都是公共 API
|
|
15
15
|
|
|
@@ -36,12 +36,12 @@ import { mount, httpSource } from "webwallgl";
|
|
|
36
36
|
|
|
37
37
|
```
|
|
38
38
|
// 2) ESM CDN(jsDelivr,vite/webpack 之外的直引方式)
|
|
39
|
-
import { mount, httpSource } from "https://cdn.jsdelivr.net/npm/webwallgl@1.
|
|
39
|
+
import { mount, httpSource } from "https://cdn.jsdelivr.net/npm/webwallgl@1.4.1/webwallgl.min.mjs";
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
```
|
|
43
43
|
<!-- 3) UMD <script>:暴露全局 WebWallGL -->
|
|
44
|
-
<script src="https://cdn.jsdelivr.net/npm/webwallgl@1.
|
|
44
|
+
<script src="https://cdn.jsdelivr.net/npm/webwallgl@1.4.1/webwallgl.global.min.js"></script>
|
|
45
45
|
<script>
|
|
46
46
|
const { mount, httpSource } = WebWallGL;
|
|
47
47
|
</script>
|
|
@@ -100,7 +100,6 @@ console.log(wp.canvas);
|
|
|
100
100
|
|
|
101
101
|
| 工厂 | 用途 |
|
|
102
102
|
| --- | --- |
|
|
103
|
-
| `1.3.16` | 2026-09-11 | 媒体组件修复与品牌化:①33 张壁纸的专辑封面此前显示黑色占位——作者把 $mediaThumbnail/$mediaPreviousThumbnail 绑在效果 pass 的 usertextures 槽,解析只取了默认占位纹理;现按绑定合并,封面正常显示(3785267658/3786330502 等)。②媒体歌名/歌手整层空白:限宽换行曾被 2×2 占位盒的内宽压成每字一行再收成省略号;文字画布改为只对占位小盒按内容对称扩边,打字机式脚本的标题不再卡在占位文本。③模拟音频改成真立体声(底鼓居中、军鼓/踩镲分左右、和弦左右独立)。④模拟媒体源换成库品牌:曲名 WebWallGL、歌手 oneincase、封面用库 logo。⑤修复共享文字画布尺寸重设后字体丢失:改 textCanvas.width/height 会重置 2D 上下文,measure 阶段设的字号被清成默认 10px,导致大字号时钟/日期按 10px 绘制、整层几乎不可见(2468489223、3379996991);现绘制用显式字体串。⑥修复时钟/日期脚本被误判为写回式而清空文本(3379996991)。 |
|
|
104
103
|
| `httpSource(baseUrl, init?)` | HTTP 基址;自动按 scene.pkg → scenes/scene.pkg → gifscene.pkg 三种真实布局回退 |
|
|
105
104
|
| `fileSource(file, project?)` | <input type=file> 或拖拽进来的 .pkg 本地文件 |
|
|
106
105
|
| `bytesSource(pkg, project?, key?)` | 已经拿到字节(bundle 内嵌、IndexedDB 缓存、自定义通道) |
|
|
@@ -123,15 +122,24 @@ input.addEventListener("change", () => {
|
|
|
123
122
|
| --- | --- | --- |
|
|
124
123
|
| `source(必填)` | `—` | 见上节 Source |
|
|
125
124
|
| `fit` | `"cover"` | cover 等比裁切铺满 / contain 等比留边 / stretch 拉伸 |
|
|
126
|
-
| `renderDpr` | `
|
|
125
|
+
| `renderDpr` | `0(自动)` | 渲染 DPR:0=跟随设备 devicePixelRatio(Retina/HiDPI 原生清晰);正数=目标 DPR,可高于设备上报值(宿主 WKWebView 误报 1 时仍能超采样到物理分辨率)。物理最长边封顶 4096,调低省显存。该档位同时决定贴图资源倍率(档位越低,贴图按图层足迹选得越小,见下节「显存与清晰度」) |
|
|
127
126
|
| `fps` | `60` | 帧率上限;被上限跳过的帧不计入 stats.fps,掉帧一眼可见 |
|
|
128
127
|
| `volume` | `0` | 0..1。默认静音起步(浏览器自动播放策略);就绪后再设非零音量 |
|
|
129
128
|
| `autoplay` | `true` | false 时挂载后保持暂停 |
|
|
130
129
|
| `properties` | `{}` | 初始用户属性覆盖值(键为属性名) |
|
|
131
130
|
| `pointer / audio / media` | `内置` | 指针跟随 canvas、音频/系统媒体为确定性模拟;传 null 禁用 |
|
|
132
131
|
| `features` | `全开` | 调试开关:models / text / particles / effects / components |
|
|
132
|
+
| `quality` | `全默认` | 渲染质量档位(对标 WE 客户端性能选项):antiAliasing: "off"(默认)/"fxaa"/"msaa2"/"msaa4"、particles: "high"(默认)/"medium"/"low"/"off"(低/中档按倍率同时缩数量上限与发射率)、postProcessing: "high"(默认)/"medium"/"low"/"off"(低/中档压效果链 FBO 分辨率;off=效果链直通+跳整屏后期层+关 Bloom)。超采样走 renderDpr |
|
|
133
133
|
| `onReady / onError / onDiagnostic` | `—` | 回调面;也可之后用 instance.on() 订阅 |
|
|
134
134
|
|
|
135
|
+
显存与清晰度:显存的大头是纹理与画布/效果链缓冲,两者都随挂载选项自动伸缩,不需要手动管理——
|
|
136
|
+
|
|
137
|
+
- 贴图按「清晰度 × 图层在屏幕上的实际足迹」自动选分辨率:只要贴图分辨率 ≥ 图层的设备像素足迹,画面与全分辨率素材逐像素一致——省掉的只是过采样。有 mip 链的图直接截链(零重采样),单级大图才重采样
|
|
138
|
+
- 压缩纹理(DXT1/3/5、BC7、ETC2)按文件自带的 mip 链直传给 GPU,不解成 RGBA;单通道 R8 走 GL_R8 直传。浏览器不支持对应扩展时自动回退解码路径,观感不变
|
|
139
|
+
- 上传完成后立即释放 CPU 侧解码副本(多帧动画 .tex 除外),最坏单墙可省数百 MB
|
|
140
|
+
- 白名单不缩:LUT 数据栅格、多帧动画、视频纹理保持原样;法线/蒙版可降但有独立下限。挂载后 window.__memStats() 给出 pkg/解码/上传的分项台账
|
|
141
|
+
- 低内存设备的推荐组合:清晰度 0.8 + 质量 low(粒子/后处理 low、抗锯齿关)。4K 屏上画布与效果链 FBO 才是大头(随 DPR 平方增长,MSAA4 再 ×4),纹理反而是其次
|
|
142
|
+
|
|
135
143
|
## 实例 API SceneInstance
|
|
136
144
|
|
|
137
145
|
| 成员 | 说明 |
|
|
@@ -139,6 +147,7 @@ input.addEventListener("change", () => {
|
|
|
139
147
|
| `pause() / resume() / paused` | 暂停恢复。禁止整包重挂:恢复时视频/音频从暂停点继续 |
|
|
140
148
|
| `setFit(fit) / setFps(n) / setVolume(v)` | 热更新,无需重挂载(渲染循环每帧读取) |
|
|
141
149
|
| `setRenderDpr(dpr)` | 改 DPR 需重建画布,内部自动重挂(pkg 缓存命中,不重新下载) |
|
|
150
|
+
| `setQuality(patch) / getQuality()` | 质量档位热更(部分更新),就地生效不重挂载;换场景/load() 后保持 |
|
|
142
151
|
| `setProperties(props)` | 属性热更新:就地改属性表/效果常量/脚本沙箱,不重新拉包 |
|
|
143
152
|
| `getProperties()` | 当前生效的扁平化属性值表 |
|
|
144
153
|
| `setAudio(src)` | 换音频频谱源(拉模式,每帧一次);null 回落内置模拟。换场景不清空。scene 与 web 都生效 |
|
|
@@ -244,7 +253,7 @@ console.log(wp.media.snapshot.title);
|
|
|
244
253
|
wp.media.playPause();
|
|
245
254
|
```
|
|
246
255
|
|
|
247
|
-
- 五个配色字段必须是可链式调用的颜色对象(脚本会写 c.subtract(o).multiply(t).add(o),给普通数组会 TypeError 熔断整个脚本)——用 createMediaSource
|
|
256
|
+
- 五个配色字段必须是可链式调用的颜色对象(脚本会写 c.subtract(o).multiply(t).add(o),给普通数组会 TypeError 熔断整个脚本)——用 createMediaSource 构造即自动满足;要手工构造时用导出的 mediaColor(r, g, b),它接受 0..1 分量、{x,y,z} 或数组,返回带完整链式方法的对象
|
|
248
257
|
- 控制方法全是可选的:只提供元数据、不支持控制时,壁纸里的按钮点了静默无效,不会报错
|
|
249
258
|
- setMedia 换场景不清空,装一次对之后所有场景生效
|
|
250
259
|
- 视频壁纸的音频频谱会自动从 <video> 取(音条能跟着视频里的音乐动),宿主已用 setAudio 显式注入时则不接管
|
|
@@ -328,102 +337,7 @@ b.pause(); // 不影响 a
|
|
|
328
337
|
|
|
329
338
|
## 版本更新说明
|
|
330
339
|
|
|
331
|
-
当前版本 1.
|
|
332
|
-
|
|
333
|
-
| 版本 | 日期 | 说明 |
|
|
334
|
-
| --- | --- | --- |
|
|
335
|
-
| `1.3.15` | 2026-09-08 | 视频对新增自愈看门狗:元素可能进入"假播放"(paused=false 但解码停摆、时间不走,无任何事件可听)导致壁纸永久冻结——渲染循环里检测可见页面上 currentTime 连续 ~500ms 不前进即 pause→play 硬重启解码;页面被遮挡时的合法节流不会误判 |
|
|
336
|
-
| `1.3.14` | 2026-09-08 | 循环交接第四版:硬切改快速淡出。爬行保证下层交接时已在运动,上层旧主元素(定格在末帧)以 64ms 线性淡出露出下层——元素级交接固有的 1~3 帧不精度(ended 分发、层交换合成)被融合窗口整体掩掉,不再依赖把每一环都压到零延迟 |
|
|
337
|
-
| `1.3.13` | 2026-09-08 | 无缝循环交接第三版「爬行」:备用在主元素最后 0.12s 以 1/8 速率实际播放(媒体管线全程 playing 态,仅前进约 1 帧),ended 触发时拨回 1x 并同步换层——速率切换是纯时钟操作,消除前两版的唤醒延迟/定格与内容跳跃 |
|
|
338
|
-
| `1.3.12` | 2026-09-08 | 无缝循环交接再调:去掉预播(双路 4K 解码瞬时争抢 + 交接处内容跳跃两个残留卡顿源),改为末帧定格——主元素 ended 后停在末帧,唤起备用并确认其真正前进再换层;定格发生在内容切点上,观感为正常剪辑切换 |
|
|
339
|
-
| `1.3.11` | 2026-09-08 | 无缝循环交接改为「预播 + ended 精确交接」:备用在主元素最后几帧就开始在其下方实际播放,主元素 ended(精确到帧,非轮询)一触发即换层 —— 消除了旧方案里恢复播放的唤醒延迟与 rAF 检测滞后带来的最后 1~2 帧卡顿 |
|
|
340
|
-
| `1.3.10` | 2026-09-08 | destroy() 新增 releasePkgCache 选项:销毁实例时连带淘汰该壁纸的 scene.pkg 解析缓存(此前切换壁纸后旧包仍留在缓存里,内存不降) |
|
|
341
|
-
| `1.3.9` | 2026-09-08 | 新增 pushWheel 滚轮 / Mac 触摸板注入通道(仅网页壁纸):合成 wheel + 旧式 mousewheel,双指捏合映射为 ctrl+滚轮;pushPointer 增加可选修饰键掩码 |
|
|
342
|
-
| `1.3.8` | 2026-09-08 | 视频壁纸改走 DOM 直显:4K 不再被降采样到 2048(清晰度)+ A/B 双元素无缝循环(循环点卡顿 84ms→33ms);场景内视频纹理层的上限也跟随渲染目标 |
|
|
343
|
-
| `1.3.7` | 2026-09-08 | 修复库入口 setRenderDpr / restore 重挂后画面全黑(复用了已 loseContext 的画布);场景壁纸支持 $mediaThumbnail 真实封面纹理 |
|
|
344
|
-
| `1.3.6` | 2026-09-08 | 新增 MediaSnapshot.thumbnail:宿主可把真实专辑封面透传给网页壁纸(此前只能给取色,封面固定是渐变占位图) |
|
|
345
|
-
| `1.3.5` | 2026-09-08 | xray 效果:作者未在场景里配置 size 时,缺省从 shader 注释的 0.2 改为 1(恒等) |
|
|
346
|
-
| `1.3.4` | 2026-09-08 | 补齐 1.3.3 遗留四项:setFit 对网页壁纸生效、audio:null 真静音、裸 iframe 回退不再帧数恒 0、调试全局随卸载清理 |
|
|
347
|
-
| `1.3.3` | 2026-09-08 | 全量审计:修 autoplay:false 挂死 mount()、scene 侧 setMedia 无效、换壁纸泄漏 AudioContext 等 |
|
|
348
|
-
| `1.3.2` | 2026-09-08 | 修复:「系统实况」麦克风此前只喂 scene,网页壁纸音谱仍是合成流 |
|
|
349
|
-
| `1.3.1` | 2026-09-08 | 修复:注入的频谱/媒体源到不了网页壁纸(音谱仍放默认流) |
|
|
350
|
-
| `1.3.0` | 2026-09-08 | mediaSource() 任意视频/图片;类型嗅探;媒体壁纸支持音量;scene 与 web 共用一套 Now Playing driver |
|
|
351
|
-
| `1.2.0` | 2026-09-08 | video 壁纸可走库入口;音频与指针注入接到公共 API(下游三项反馈) |
|
|
352
|
-
| `1.1.0` | 2026-09-07 | 外部指针注入通道、网页壁纸交互、效果 pass 编译清零、暂停语义补全 |
|
|
353
|
-
| `1.0.0` | 2026-09-06 | 首个正式版:公共 API 定稿(mount / SceneInstance / Source 三件套) |
|
|
354
|
-
| `1.0.0-beta1` | 2026-09-04 | 首个公开测试版 |
|
|
355
|
-
|
|
356
|
-
1.3.9 加的是滚轮注入通道。指针注入(pushPointer)一直只有位置与按键,没有滚轮 —— 桌面壁纸窗口收不到鼠标事件,自然也收不到滚轮。但这次扫了本机全部 256 张壁纸后发现范围比预想窄:194 张场景壁纸零滚轮消费(WE 的场景脚本沙箱根本没有滚轮 API,场景包里所有 scroll 字样都是纹理滚动图层效果 g_ScrollSpeed),只有网页壁纸用得上;而 52 张网页壁纸里真正消费滚轮的只有一张 360° 全景(3406740580,滚轮改视角 FOV),外加 three.js OrbitControls 默认开启的一张。麻烦的是这张全景只听旧式 mousewheel / DOMMouseScroll,不听现代 wheel,而 OrbitControls 又只听现代 wheel —— 只合成任意一种都会让另一类壁纸完全无反应,且没有任何报错。所以网页侧每次推送同时派发现代 wheel 与旧式 mousewheel(wheelDelta 与 deltaY 反号、detail 置 0);刻意不发 DOMMouseScroll,因为三个旧式消费方每一个都把它和 mousewheel 绑到同一个处理函数上,三个都发等于同一次滚动处理两遍,FOV 一次跳两格,看起来只是「滚轮太灵敏」。Mac 触摸板的适配是重点:双指滚动直接是像素级 wheel(deltaMode=0),双指捏合则按浏览器约定翻译成 ctrl 位为真的 wheel(OrbitControls / pano2vr 都靠 event.ctrlKey 区分缩放与滚动),宿主从 NSEvent.magnify 映射时注意 scrollingDeltaY 要取反。滚轮位置沿用最后一次指针坐标。场景壁纸调用 pushWheel 静默无效,与视频等媒体壁纸同样处理。
|
|
357
|
-
|
|
358
|
-
1.3.8 是一组视频壁纸的改动,起因是 4K 视频看起来发糊。原因不在任何清晰度设置,而是视频帧过去要先上传成 WebGL 纹理,那条路径有个写死的 2048 长边上限 —— 3840×2160 的源被降到 2048×1152(面积只剩 28%)再放大铺满屏幕,而 Retina 上渲染目标常见 3024 甚至 3840,等于把一张 2K 图放大给你看。现在视频类型直接用 `<video>` 显示,不再经纹理:浏览器按显示尺寸硬件解码合成,拿到原生分辨率,还省掉一个 WebGL 上下文和每帧一次全画布上传。代价是纯视频壁纸没有效果链/粒子叠加能力,它本来也用不到;「场景内含视频纹理层」的壁纸不走这条路,但那条路径的上限也一并改成了 min(硬件 MAX_TEXTURE_SIZE, 渲染目标长边, 3840) —— 上传比渲染目标更大的纹理是纯浪费,多出的像素在采样阶段就被丢掉。
|
|
359
|
-
|
|
360
|
-
同一版还接上了无缝循环。WebKit 的 `<video loop>` 在循环点会重置解码管线,缓冲再充分也躲不掉 —— 实测 3840×2160@60fps 的 12 秒素材,循环点最坏帧间隔 84ms(约卡 5 帧)。库里本来就有 A/B 双元素方案(主元素临近结尾时备用起播一两帧后暂停保温,真到结尾的 2~5 帧内交接),只是没接到视频壁纸上,而当初 DOM 路径注释里写着「放弃双元素,内存减半」。这个说法经实测是错的:备用元素平时**不赋 src**,只在结尾前 0.5s 窗口才预热,12 秒视频里重叠占比不到 5%,进程 RSS 峰值从 128MB 到 130MB,而循环点最坏间隔降到 33ms。所以它默认开启,没有开关。备用未及时就绪时自动退回原生 loop,只是回到旧表现,不会中断或黑屏。附带修掉的:`pause`/`resume`/`setVolume`/`setFit` 过去只认场景实例,对 DOM 视频静默失效;DOM 路径不上报首帧会让 `mount()` 的 Promise 永久挂起;不持续打点会让 `instance.stats` 恒报「已停」。判活刻意用 rAF 而非 requestVideoFrameCallback —— 后者在 WKWebView 里存在却从不回调(视频正常播放时 1.5 秒 0 次)。
|
|
361
|
-
|
|
362
|
-
1.3.7 两项,都在「卸载后重挂」这条路上。一是库入口的 setRenderDpr 与 restore 重挂后画面全黑:清理阶段 renderer.dispose() 走的是 WEBGL_lose_context.loseContext(),而按规范同一个 canvas 之后再 getContext("webgl2") 拿回的仍是那个已丢失的上下文对象(实测新旧引用相同、isContextLost() 为真),只有换一块新画布才能拿到可用上下文。整页渲染器不踩是因为它清理时把容器 innerHTML 清空、画布跟着删掉;库形态没有那层容器,画布被留下复用,于是宿主一改清晰度就黑屏,而且两个方法都不挂首帧守卫,连报错都没有。现在复用前先查上下文存活,死了就换新画布,调用方直接传 canvas(库不能替它换 DOM)时如实报错。二是场景壁纸的封面:它不像网页壁纸走脚本回调,作者是把 $mediaThumbnail / $mediaPreviousThumbnail 这两个 WE 保留纹理名直接填进层的 image / textures 槽,所以 1.3.6 加的 MediaSnapshot.thumbnail 对场景侧原本没有意义。现在快照里的封面变化会异步解码并上传成 GL 纹理(旧的顺位挪到 $mediaPreviousThumbnail),与「系统实况」原有的上传逻辑共用同一段像素代码。
|
|
363
|
-
|
|
364
|
-
1.3.6 只有一项,补的是媒体快照里缺的封面通道。此前 MediaSnapshot 只有 hasThumbnail 和五个取色字段,没有图片本体:网页壁纸的 mediaThumbnailChanged 收到的 event.thumbnail 是库拿 primary/secondary 现画的 64×64 渐变块,语料里 `img.src = e.thumbnail` 那类写法能跑但显示的不是真封面。现在 MediaSnapshot 与 createMediaSource 都多一个可选的 thumbnail(data URL 或同源 URL),宿主填了就原样透传给壁纸,没填仍走渐变占位图;只给 thumbnail 不给 hasThumbnail 时后者自动为真。另外事件 diff 也把 thumbnail 纳入判定 —— 系统媒体接口普遍先给歌名再补封面,只看 hasThumbnail/trackIndex 会漏掉「同一首歌补上封面」这一次变化。场景(WebGL)壁纸在本版本里还用不上它:它们的脚本只读 hasThumbnail 与取色,图片本体要走保留纹理(见 1.3.7)。
|
|
365
|
-
|
|
366
|
-
1.3.5 只有一项,改的是 xray 效果的缺省值。xray 的 size 决定效果范围(内部取倒数,size=1 是恒等)。作者若没在场景的 constantshadervalues 里写 size,此前会套用 shader 声明注释里的 "default":0.2 —— 但那是 WE 编辑器新建效果时滑条的初始位置,不是运行时缺省:编辑器一旦把效果加到层上就会把当时的滑条值写进场景文件,所以官方运行时永远读得到显式值。套 0.2 会让效果范围缩成五分之一,只剩光标旁一小块。现在缺省是 1。作用面收窄在这一个参数上,multiply 与贴图槽的注释缺省不变。
|
|
367
|
-
|
|
368
|
-
1.3.4 收掉 1.3.3 结尾列为「留待后续」的四项,都是能观测到的行为偏差,不是清理式重构:
|
|
369
|
-
|
|
370
|
-
- **setFit() 对网页壁纸不生效**:它只改了配置和 cover 对齐量,而网页壁纸的缩放是靠一次布局计算写进 iframe 的 transform 的,不重排就还是旧比例。现在 setFit 会触发重排(场景与媒体壁纸本来就每帧读配置,不受影响)
|
|
371
|
-
- **注入 shim 失败退回裸 iframe 后帧率恒 0**:这条路径不启动任何 rAF,统计里没人推进帧计数,宿主看到的是「壁纸挂了」。回退分支补上心跳 rAF,帧率与实际刷新一致
|
|
372
|
-
- **audio:null 在网页壁纸上不是静音,而是退回合成流**:判定只看「有没有设过注入源」,分不清「显式禁用」与「没设置」。现在两者分开,audio:null / media:null 在 scene 与 web 上都真的关掉(setAudio(src) 会重新打开)
|
|
373
|
-
- **调试全局不随卸载清理**:__scene / __textures 等 19 个诊断入口在 clear() 后仍挂在 window 上,指着已销毁场景的对象图,既让上一张壁纸的纹理和层树无法回收,也会让宿主在控制台里读到过期状态。改为 clear() 时逐个删除
|
|
374
|
-
|
|
375
|
-
1.3.3 是一次覆盖「漏接 / 缺陷 / 内存泄漏」三类的全量审计,修掉的都是实测确认的问题:
|
|
376
|
-
|
|
377
|
-
- **autoplay:false 会让 mount() 永久挂起**(scene 与媒体壁纸):装配前就置 paused,渲染循环一帧都不跑,唯一触发首帧回调的地方永远到不了,Promise 既不 resolve 也不 reject。实测同一张壁纸默认能 resolve、autoplay:false 在 rAF 活跃 500 帧后仍 pending。改为照常装配、首帧画完再暂停
|
|
378
|
-
- 首帧回调改到 render() **完成之后**触发(此前排在 render 调用之前,早一帧落地,autoplay:false 会拿到一张空画布)
|
|
379
|
-
- **setMedia() 在场景壁纸上无效**:scene 把 media driver 在装配时一次性捕获,而 setMedia 通常在 mount() 之后才调用。改为每次读取重新选(web 侧本来就是这样)
|
|
380
|
-
- **换壁纸会泄漏 AudioContext**:视频壁纸的频谱接管把释放登记在实例级列表里,而换壁纸走的是 clear(),只有 destroy() 才排空。浏览器约 6 个 AudioContext 就到顶,之后音频响应静默失效。新增壁纸级释放列表,clear() 逐张排空
|
|
381
|
-
- **清理链一处抛异常会丢掉整个 teardown**:clear() 里调用装配层清理没有 try/catch,一旦抛出,后面的 WebGL 上下文释放、视频元素回收、blob revoke 全部跳过
|
|
382
|
-
- **麦克风授权期间换壁纸会漏掉麦克风流**:getUserMedia 阻塞在系统弹窗上,此前的释放登记写在 await 之后,这条路径上没人会调它,浏览器录音指示一直亮着。两条装配路径都改为同步登记释放槽
|
|
383
|
-
- instance.media 控制面在 clear() 时重置(此前 release()/destroy() 之后它仍指向已销毁场景的沙箱闭包)
|
|
384
|
-
|
|
385
|
-
已知仍未接线(有意为之,类型注释已标注):MountOptions 的 pointer 与 features。外部喂指针请用 pushPointer()。
|
|
386
|
-
|
|
387
|
-
1.3.2 补上同一症状的**第二条通道**:1.3.1 修的是宿主注入(setAudio),而测试台「系统实况」勾选框走的是另一条路(cfg.liveSystem,库自己采麦克风),它此前只被 scene 装配路径消费——web.ts 里 liveSystem 零引用,所以勾上之后场景壁纸的音条跟着麦克风动、网页壁纸却始终是合成流。
|
|
388
|
-
|
|
389
|
-
- 网页壁纸现在也接系统实况麦克风,与 scene 用同一份采集(startLiveSystem)
|
|
390
|
-
- 麦克风采集是异步的(getUserMedia 要用户授权),不阻塞泵启动:先按默认源跑,授权通过后回填、由逐帧选源切过去
|
|
391
|
-
- 音频源优先级:宿主注入(setAudio)> 系统实况麦克风 > 内置模拟
|
|
392
|
-
- 卸载时释放麦克风流(否则浏览器地址栏的录音指示会一直亮着)
|
|
393
|
-
|
|
394
|
-
1.3.1 修一个下游实测发现的缺陷:**麦克风都接上了,网页壁纸的音谱还在放默认合成流**。
|
|
395
|
-
|
|
396
|
-
- 根因一:web 装配路径压根不读 rt.audioBridge(1.3.0 给媒体源接了这一环,音频这行漏了),注入的频谱到不了 iframe
|
|
397
|
-
- 根因二:音频与媒体两个泵都在**装配时**捕获 driver,而 setAudio()/setMedia() 通常在 mount() 之后才调用(宿主的麦克风 / SSE 通道那时才就绪)——定死 driver 等于后装的源永远不生效。两个泵均改为逐帧选源,撤源后也能落回默认
|
|
398
|
-
- 注入的频谱**不再套 gamma 对比扩展**:那道处理是给内置模拟源的未钳位频段用的,对宿主给的 0..1 真实频谱再乘一遍会把音条整体顶到满格
|
|
399
|
-
|
|
400
|
-
1.3.0 是 1.2.0 的直接延续,继续按下游宿主的反馈补齐(四项):
|
|
401
|
-
|
|
402
|
-
- 新增 mediaSource(urlOrFile):任意视频/图片可直接当壁纸,支持远程 URL 与本地 File(拖拽导入)。本地文件的 objectURL 由库在 destroy()/换源时自动 revoke——不 revoke 就是每换一次壁纸泄漏一个几十 MB 的 blob
|
|
403
|
-
- 类型嗅探:project.type 缺失时按 URL 扩展名判定(正确剥掉签名 URL 的 ?query 与 #hash),认不出才落回 scene。显式声明的 project.type 永远优先,不会被嗅探覆盖
|
|
404
|
-
- 媒体壁纸现在支持 setVolume(此前完全无效:音量只打到 scene 的音频节点)。同时写 volume 与 muted——<video muted> 下只改 volume 一点用都没有;取消静音被自动播放策略拒绝时经 onDiagnostic 如实报出,不静默吞掉
|
|
405
|
-
- MediaSource 扩成 driver 的真实契约(18 字段快照 + 5 个可选控制方法),并由 scene 与 web **共用同一个实例**——此前两侧各自 new 一份模拟源,宿主无从注入。新增 createMediaSource() 只需给已知字段,配色/歌词行/trackIndex 由库补齐并保证颜色是可链式调用的实例
|
|
406
|
-
- 新增 SceneInstance.setMedia() 与 media 控制面(读快照 + 上一曲/下一曲/播放暂停),反向控制直接转发给宿主 driver;宿主更新数据后引擎同帧可见
|
|
407
|
-
- 视频壁纸的频谱自动从 <video> 取,音条能跟着视频里的音乐动;宿主已用 setAudio 显式注入时不接管
|
|
408
|
-
|
|
409
|
-
1.2.0 补的是三个「运行时早就能跑、只是公共库入口没接出来」的缺口(由下游宿主 wallpaperEM 反馈):
|
|
410
|
-
|
|
411
|
-
- video / gif / image 壁纸现在能经 mount() 挂载:新增 Source.mediaEntry() 取址,并补齐媒体路径的库化契约。此前媒体路径不触发 onFirstFrame / onError,即便接上分流,mount() 的 Promise 也会永久挂起——成功不 resolve、失败不 reject
|
|
412
|
-
- 媒体路径改为支持调用方传入的 canvas,并按 CSS 尺寸而非窗口尺寸分配缓冲区(此前嵌入式画布会拿到整窗口大小的 backing store,且画布根本不会被插入 DOM)
|
|
413
|
-
- MountOptions.audio 真正接线(此前是声明了却零引用的死字段),并新增 SceneInstance.setAudio() 供挂载后切换——宿主的频谱通道常在 mount() 之后才就绪
|
|
414
|
-
- 新增 SceneInstance.pushPointer() / pointerLeave(),与整页渲染器的 __wp 同名同签名,下游从整页迁到库时代码不用改
|
|
415
|
-
- 已知边界(当时状态):音频注入只对 scene 生效——网页壁纸走 iframe shim 的另一条通道,1.3.1 已补上;媒体壁纸没有指针概念;MountOptions 的 pointer / media / features 当时未接线(media 已在 1.3.0 接线)
|
|
416
|
-
|
|
417
|
-
1.1.0 的内容(在 1.0.0 之后合入):
|
|
418
|
-
|
|
419
|
-
- 新增外部指针注入通道 __wp.pushPointer / pointerLeave:桌面壁纸窗口收不到鼠标时(如 macOS 下 Finder 桌面窗口吃掉事件),由宿主轮询系统鼠标后推进来。场景与网页两类壁纸共用同一套协议,调用方不必判断类型
|
|
420
|
-
- 网页壁纸接入同一条注入通道:shim 按命中元素合成 DOM 事件(over/out/enter/leave 链完整、click 靠按键边缘合成)。本机库 49 张网页壁纸里 mousemove 24 / click 29 / pointer* 16 张的交互从「完全无反应」变为可用。硬限制:CSS :hover 由浏览器 hit-test 驱动,合成事件点不亮
|
|
421
|
-
- 效果 pass 编译失败清零(七批):转译器修掉整浮混用、宏作用域、向量收窄、科学计数法等形态。全库效果 pass 编译通过率 1653/1873 (88.3%) → 1823/1873 (97.3%),累计 +170。症状是「某个效果静默不出现」——编译失败只 warn 不报错,画面上表现为体积光/音谱/光晕整个缺失
|
|
422
|
-
- 暂停语义补全:暂停必须同时冻结 rAF/定时器与 CSS 动画(合成器驱动的 CSS 动画不受 JS 冻结影响,1444432396 表现为「点了暂停画面照旧」);恢复必须重挂 rAF 挂起项(rAF 自递归的壁纸暂停一次就永久断链,1278092907 表现为「恢复后永久定格」),且只还原我们代为暂停的部分
|
|
423
|
-
- 还原度修复若干:关键帧动画改用真实时钟(此前按目标帧间隔累加,与骨骼两套时基必然发散,30 秒漂 5.5 秒,表现为头发与头不同步、头顶漏模);对象脚本与关键帧动画的坐标空间改为 local 并每帧重算父子变换(此前把脚本返回的 local 值直接写进 world 槽,表现为元素无人操作就自行滑走、被边缘裁切);clipping_mask 引用的隐藏遮罩层现在能正确回读身后画面(此前回退成引用方自身,表现为一块纯白板)
|
|
424
|
-
- 使用说明新增「挂载目标」与「用户属性」两节:网页壁纸必须传容器 div 而非 canvas,以及各类属性该传什么形态的值
|
|
425
|
-
|
|
426
|
-
完整提交历史见 GitHub 仓库;每条修复在提交信息里都写明了症状、根因、影响面数字与验证方式。
|
|
340
|
+
当前版本 1.4.1。这里不再维护逐版本列表:每一次变化的症状、根因、影响面数字与验证方式都写在对应的提交信息里,完整历史见 GitHub 仓库的提交记录与 Release。
|
|
427
341
|
|
|
428
342
|
## 版权与合规
|
|
429
343
|
|
package/package.json
CHANGED
package/types.d.ts
CHANGED
|
@@ -244,6 +244,28 @@ export type FeatureFlags = {
|
|
|
244
244
|
/** WE 内置组件对象(本机库 0 个,真出现时按开关处理) */
|
|
245
245
|
components: boolean;
|
|
246
246
|
};
|
|
247
|
+
/** 抗锯齿模式。off=关闭(默认);fxaa=帧末后处理抗锯齿(平滑所有边缘,含纹理
|
|
248
|
+
* alpha 边);msaa2/msaa4=多重采样(只平滑几何边缘,与 WE 的 MSAA 语义一致)。
|
|
249
|
+
* 单选不叠加。 */
|
|
250
|
+
export type AntiAliasingMode = "off" | "fxaa" | "msaa2" | "msaa4";
|
|
251
|
+
/** 粒子质量档。off=不渲染不推进;low/medium 按倍率同时缩 maxcount 上限与
|
|
252
|
+
* 发射率;high=原始配置(默认)。 */
|
|
253
|
+
export type ParticleQuality = "off" | "low" | "medium" | "high";
|
|
254
|
+
/** 后处理质量档。off=图层效果链直通 + 跳过整屏后期层 + 关内置 Bloom;
|
|
255
|
+
* low/medium/high=效果链开启,仅效果链 FBO 分辨率预算不同。 */
|
|
256
|
+
export type PostQuality = "off" | "low" | "medium" | "high";
|
|
257
|
+
/** 质量设置(缺省键按默认值补全:AA off / 粒子 high / 后处理 high) */
|
|
258
|
+
export type QualityOptions = {
|
|
259
|
+
antiAliasing?: AntiAliasingMode;
|
|
260
|
+
particles?: ParticleQuality;
|
|
261
|
+
postProcessing?: PostQuality;
|
|
262
|
+
};
|
|
263
|
+
/** 三项齐全的规范化结果(getQuality / normalizeQuality 的输出) */
|
|
264
|
+
export type ResolvedQuality = {
|
|
265
|
+
antiAliasing: AntiAliasingMode;
|
|
266
|
+
particles: ParticleQuality;
|
|
267
|
+
postProcessing: PostQuality;
|
|
268
|
+
};
|
|
247
269
|
/** 场景装配完成后的基本信息 */
|
|
248
270
|
export type SceneInfo = {
|
|
249
271
|
/** 场景逻辑分辨率(scene.json 的 general.orthogonalprojection) */
|
|
@@ -269,8 +291,11 @@ export type MountOptions = {
|
|
|
269
291
|
/** 适配模式。默认 "cover" */
|
|
270
292
|
fit?: Fit;
|
|
271
293
|
/**
|
|
272
|
-
*
|
|
273
|
-
*
|
|
294
|
+
* 渲染分辨率 DPR,决定 backing store = CSS 像素 × DPR。
|
|
295
|
+
* - 0 或不传(默认):自动跟随设备 devicePixelRatio,Retina/HiDPI 屏原生清晰;
|
|
296
|
+
* - 正数:目标 DPR,**允许高于设备上报值**(某些壁纸宿主 WKWebView 把
|
|
297
|
+
* devicePixelRatio 报成 1,传 2 仍按 2 超采样到物理分辨率);
|
|
298
|
+
* 物理最长边封顶 4096 防爆显存,超出等比回收。调低(如 1)可省显存。
|
|
274
299
|
*/
|
|
275
300
|
renderDpr?: number;
|
|
276
301
|
/** 帧率上限。默认 60。渲染循环跳过比目标更快的帧,降低 GPU 占用 */
|
|
@@ -298,6 +323,12 @@ export type MountOptions = {
|
|
|
298
323
|
media?: MediaSource | null;
|
|
299
324
|
/** 渲染开关(调试用)。**当前未接线** */
|
|
300
325
|
features?: Partial<FeatureFlags>;
|
|
326
|
+
/**
|
|
327
|
+
* 渲染质量设置(抗锯齿/粒子/后处理档位,见 quality.ts)。
|
|
328
|
+
* 缺省 = 全默认(AA off、粒子 high、后处理 high),与引入前的行为一致。
|
|
329
|
+
* 挂载后可用 `SceneInstance.setQuality()` 热调。
|
|
330
|
+
*/
|
|
331
|
+
quality?: QualityOptions;
|
|
301
332
|
/** 诊断回调。替代旧的 GET /diag 上报 */
|
|
302
333
|
onDiagnostic?: SceneEvents["diagnostic"];
|
|
303
334
|
/** 装配或渲染失败。库不自带降级页,由调用方决定怎么兜 */
|
|
@@ -321,6 +352,14 @@ export type SceneInstance = {
|
|
|
321
352
|
setVolume(volume: number): void;
|
|
322
353
|
/** 改 DPR 需重建画布尺寸,内部自动重挂当前场景 */
|
|
323
354
|
setRenderDpr(dpr: number): void;
|
|
355
|
+
/**
|
|
356
|
+
* 渲染质量设置热更(对标 WE 客户端的性能选项:抗锯齿/粒子/后处理档位)。
|
|
357
|
+
* 部分更新:只传要改的键。**就地生效,不重挂载**(与 setRenderDpr 不同)。
|
|
358
|
+
* 换场景/load() 之后保持(与 setAudio 同纪律,合并进挂载选项)。
|
|
359
|
+
*/
|
|
360
|
+
setQuality(patch: QualityOptions): void;
|
|
361
|
+
/** 当前生效的质量设置(三项齐全,缺省键已按默认值补全) */
|
|
362
|
+
getQuality(): ResolvedQuality;
|
|
324
363
|
/**
|
|
325
364
|
* 用户属性热更新。就地改属性表 / 效果常量 / 脚本沙箱,
|
|
326
365
|
* **不重新拉取与解析 scene.pkg**(百 MB 包重挂是可感知的卡顿)。
|
package/webwallgl.d.ts
CHANGED
|
@@ -37,6 +37,11 @@ import type {
|
|
|
37
37
|
MediaSourceInit,
|
|
38
38
|
MediaSourceControls,
|
|
39
39
|
DiagnosticLevel,
|
|
40
|
+
AntiAliasingMode,
|
|
41
|
+
ParticleQuality,
|
|
42
|
+
PostQuality,
|
|
43
|
+
QualityOptions,
|
|
44
|
+
ResolvedQuality,
|
|
40
45
|
} from "./types";
|
|
41
46
|
|
|
42
47
|
export type {
|
|
@@ -60,6 +65,11 @@ export type {
|
|
|
60
65
|
MediaSourceInit,
|
|
61
66
|
MediaSourceControls,
|
|
62
67
|
DiagnosticLevel,
|
|
68
|
+
AntiAliasingMode,
|
|
69
|
+
ParticleQuality,
|
|
70
|
+
PostQuality,
|
|
71
|
+
QualityOptions,
|
|
72
|
+
ResolvedQuality,
|
|
63
73
|
};
|
|
64
74
|
|
|
65
75
|
export declare function mount(
|
|
@@ -91,6 +101,11 @@ export declare function sniffMediaType(
|
|
|
91
101
|
url: string,
|
|
92
102
|
): "video" | "gif" | "image" | null;
|
|
93
103
|
|
|
104
|
+
/** 从 Source.key 末段抽出工坊 ID(视差白名单 / 脚本 __workshopId 回填用) */
|
|
105
|
+
export declare function workshopIdFromSourceKey(
|
|
106
|
+
key?: string | null,
|
|
107
|
+
): string | undefined;
|
|
108
|
+
|
|
94
109
|
export declare function createMediaSource(
|
|
95
110
|
init?: MediaSourceInit,
|
|
96
111
|
controls?: MediaSourceControls,
|