-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Comparing changes
Open a pull request
base repository: playcanvas/engine
base: v2.19.1
head repository: playcanvas/engine
compare: v2.19.2
- 9 commits
- 32 files changed
- 6 contributors
Commits on May 29, 2026
-
Configuration menu - View commit details
-
Copy full SHA for 62c484d - Browse repository at this point
Copy the full SHA 62c484dView commit details
Commits on Jun 1, 2026
-
feat(examples): share dialog with state-encoded URLs (#8796)
* feat(examples): persist app state in url hash Adds examples/src/app/url-state.mjs and wires it into Sidebar, Menu, MainLayout, Example, CodeEditor, and DeviceSelector so that UI state (sidebar collapsed, filter, fullscreen, mobile panel, control overrides, device, selected file) survives reloads and is shareable via the hash. State is serialized one-way as a base64 JSON blob in ?s=. Recipient reads it on initial load only; browser back/forward and manual URL edits do not sync mid-session. Control overrides use a 2s settle-window heuristic so async-init observer mutations (e.g. gsplat lod-streaming's assetListLoader.load callback) update the local baseline rather than polluting the URL. URL-provided overrides are re-applied if the example tries to clobber them during the window. * perf(examples): deflate + base64url url-state for smaller share links Wraps the JSON payload in fflate's deflateSync before base64url-encoding, and shortens the top-level keys (device->d, ui->u, controls->c) before serialization. For a worst-case gsplat default-state dump this cuts the ?s= from 500 to 338 chars (~32%); typical user-diff payloads drop from ~128 to ~98 chars. base64url avoids the +/= chars that URLSearchParams URL-decodes incorrectly on read, so the encoded value round-trips cleanly through window.location.hash without manual escaping. * fix(examples): recursive leaf-level diff for url controls Top-level diff was dumping entire nested control trees (e.g. the orbit example's `attr` namespace) when only one leaf changed. Now walks both baseline and current in parallel and emits flat dot-paths for the specific leaves that differ. Also switches baseline capture to a one-shot snapshot at settle-window end (via setTimeout) so async-init values like orbit's `data.set('attr', { ...defaults })` after `app.start()` are folded into baseline cleanly instead of being tracked path-by-path. Re-apply logic for URL overrides during settle now handles the case where the example writes a parent of the overridden path (e.g. URL has `attr.rotateSpeed=0.1` and example does `data.set('attr', { whole defaults })` — every overridden leaf under `attr.` is re-applied). For the user's orbit case (2 changed leaves under attr): payload drops from ~280 to ~138 chars. * feat(examples): copy-to-clipboard share button + crawler-friendly share page Replace the legacy tweet button with a share button that copies a state- encoded URL to the clipboard. Inline SVG share-2 glyph (Feather), flex- centered to match the icon-font buttons, with orange-flash + checkmark swap feedback for 1.5s after a successful copy. buildShareUrl now targets `${origin}/share/<category>_<example>/?s=...` so shared links flow through the crawler-friendly share page. Falls back to the canonical hash URL on the index route. Rewrite templates/share.html from a meta-refresh redirect into a thin SPA-bootstrap page: - per-example twitter:card + og:* meta tags - absolute asset paths so they resolve from /share/<slug>/ - inline script history.replaceState's to /#/<path>?s=... before the bundle boots, forwarding the ?s= state; recipient lands directly on the SPA with no visible interstitial. Fixes the previous template's broken twitter:url (`playcanvas.github.io/ <path>` 404'd since the SPA uses hash routing) and meta-refresh dropping the ?s= state. The share-page origin is resolved at build time from `VERCEL_URL` (every Vercel preview/production deploy gets its own self-referential meta), with `SHARE_ORIGIN` env override and a `playcanvas.vercel.app` fallback for local prod-target builds. Dev server passes the request's own scheme+host so localhost browsing yields localhost meta tags. Rename `utils/build-shared.mjs` -> `utils/build-examples.mjs` (the module exports the whole example-build pipeline, not just shared utilities). Update importers in build-prod, vite-dev-server, thumbnails. Split writeShareHtml into createShareHtml (returns string) + writeShareHtml (writes to disk) so the dev server can render the page inline without staging dist/. Drop the production-only gate on share-page generation so dist/share/* exists for local preview builds too. Add a /share/<slug>/ route to the vite dev server using createShareHtml. Add `#shareButton.selected` to the existing menu .selected CSS rule so the click feedback actually shows. * chore(examples): drop unrelated changes from url-state branch Revert the gizmo snap-increment override logic and colorAlpha removal in misc/editor and the stray comment removal in gaussian-splatting/lod- streaming. Neither was needed for url-state persistence or the share flow; keeping the PR to the minimal diff for that task. * feat(examples): share dialog with social buttons and copy link Replace the immediate-copy share button with a "Share this page" modal modelled on super-splat's. Click the share icon → dialog with title + close, four platform-colored social buttons (Facebook / Reddit / X / LinkedIn) that open the platform's intent URL in a popup, a "OR COPY LINK" divider, a read-only URL input, and a Copy button that shows a "Copied" state for ~1.5s. ShareDialog.mjs is a new self-contained component. It calls buildShare- Url() lazily on each open so the URL reflects current state, derives a "<example name> - PlayCanvas Examples" title from the hash path, opens each social intent via window.open(..., 'noopener,noreferrer,width=600, height=400'), and closes on backdrop click, X button, or Escape. Styling keys off the examples overlay palette so the dialog reads as a native surface, not a bolt-on: rgba(54, 67, 70, 0.95) panel, 6px radius, 14px title, 40px brand-colored socials (4px radius), 30px input + copy button — all in line with the description/credits overlays and the 32px menu rhythm above. * fix(examples): capture control baseline early on user interaction The 2s settle window was meant to let example async-init `data.set` calls land in the baseline before user diffs start tracking. But if the user changes a control inside that window (e.g. pasting a Scene.url into gaussian-splatting/lod-streaming right after the page loads), the modified value gets folded into the baseline at settle end and so never appears in the shared URL — even though subsequent changes outside the window do. Capture the baseline as soon as the user interacts with #controlPanel (via document-level capture-phase pointerdown/focusin), whichever comes first. Async-init writes that fire before the user touches anything still flow into the baseline as intended; anything after the first interaction is treated as a real user diff. * Revert "fix(examples): capture control baseline early on user interaction" This reverts commit d33f3b4. * fix(examples): lod-streaming respects share-URL Scene.url override app.start() fires 'start' synchronously, which in turn fires the exampleLoad event and runs Example.mjs's applyControlState — all before the example reaches its explicit loadGsplat call. applyControlState writes the share-URL state value into observer.url, but the example's url:set handler isn't registered yet, so the load isn't triggered. Then the explicit `await loadGsplat(paramUrl || null)` ignores the observer value and loads the default. Read the observer's url (populated by applyControlState OR by the example's own paramUrl-driven data.set) for the initial load instead of hardcoding paramUrl. Other cases (no override, ?url= hash, future user edits via the url:set handler) are unchanged.Configuration menu - View commit details
-
Copy full SHA for 0282eba - Browse repository at this point
Copy the full SHA 0282ebaView commit details
Commits on Jun 3, 2026
-
feat(webgpu): support HTML-in-Canvas textures via copyElementImageToT…
…exture (#8810) * feat(webgpu): support HTML-in-Canvas textures via copyElementImageToTexture Adds WebGPU support for the HTML-in-Canvas API, previously WebGL-only. Generic HTML elements can now be used as live texture sources on the WebGPU backend. - WebGPU device reports supportsHtmlTextures = true when the browser exposes queue.copyElementImageToTexture - WebGPU 2D texture uploads route generic HTML elements through a new copyElementImageToTexture path - Updated html-texture and html-texture-configurator examples * update --------- Co-authored-by: Martin Valigursky <mvaligursky@snapchat.com>
Configuration menu - View commit details
-
Copy full SHA for ef37e84 - Browse repository at this point
Copy the full SHA ef37e84View commit details -
fix: update HTML-in-Canvas texture upload to new API (#8828)
WebGPU copyElementImageToTexture now takes source and destination dictionaries instead of positional args. WebGL texElementImage2D now takes (target, internalformat, element), dropping level/srcFormat/destType. Co-authored-by: Martin Valigursky <mvaligursky@snapchat.com>
Configuration menu - View commit details
-
Copy full SHA for 90802d4 - Browse repository at this point
Copy the full SHA 90802d4View commit details -
docs: replace opaque any/* types with real types in public API refere…
…nce (#8811) Two public, reference-visible members documented their JSDoc types as the opaque `*`/`any`, which renders as a meaningless `any` in the generated TypeDoc API reference: - `RenderTarget.getColorBuffer(index)` - `index` is an array index, typed `{*}` -> `{number}`. - `InputConsumer.update()` - the base method discards the frame and returns nothing, so the bogus `@returns {any}` is dropped (per the engine convention of omitting `@returns` when nothing is returned); the `InputController` subclass override already documents its `{Pose}` return. Both compile cleanly (build:types/test:types); the generated declarations now read `getColorBuffer(index: number): Texture` and `InputConsumer.update(...): void` / `InputController.update(...): Pose`. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 2e4455a - Browse repository at this point
Copy the full SHA 2e4455aView commit details -
docs: fix @param names/types that contradict the function signatures (#…
…8813) Four JSDoc `@param` blocks documented names (and in two cases types) that did not match the actual parameters, surfaced by enabling jsdoc/check-param-names (currently off in the shared config): - `Morph._createTexture` documented `levels` before `arrayLength`, but the signature is `(name, format, arrayLength, levels)` - so the emitted types were swapped (`arrayLength` as `{Array}`, `levels` as `{number}`). Reordered to match. - `XrViews.update` documented `xrView` (`{XRView}`); the parameter is `xrViews` and is iterated as an array, so corrected to `{XRView[]} xrViews`. - `WebgpuXrBridge.getFramebufferSize` / `getViewport` documented `frame`; the parameter is the intentionally-unused `_frame`. Matched the docs to it. Verified: jsdoc/check-param-names reports 0 mismatches, lint clean, build:types/test:types pass. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 537521a - Browse repository at this point
Copy the full SHA 537521aView commit details -
docs: elevate the Entity class reference to peak quality (#8814)
First page in a page-by-page effort to bring flagship API reference pages up to the standard already set by the best pages (e.g. GSplatComponent, Vec3). - Rewrites the Entity class overview into an authored introduction: the mental model (a scene-graph node plus a set of components), the two facets it combines (transform from GraphNode + components), and the typical workflow (addComponent / accessor / removeComponent / enabled / destroy), with tight cross-links to Component, GraphNode, AppBase#root and the common components. - Adds two canonical, runnable class-level `@example`s (create a camera entity and add it to the scene; parent/child transform inheritance). - Fixes an accuracy bug: `findComponent()` was typed `{Component}` but actually returns `null` when nothing is found (via `GraphNode#findOne`) - now `{Component|null}`. The 21 component accessors are intentionally left terse, and the other methods were already at the bar. Verified: lint clean, docs build with 0 errors and no new warnings, build:types and test:types pass (`findComponent(type: string): Component | null`). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Configuration menu - View commit details
-
Copy full SHA for c90406c - Browse repository at this point
Copy the full SHA c90406cView commit details -
fix(gsplat): apply material changes made in frame:ready the same frame (
#8830) Material state changed from a frame:ready event listener (e.g. app.scene.gsplat.antiAlias = ...) was silently dropped: the renderer's per-frame material sync ran before the event fired, and frameEnd() cleared the material dirty flag before any later frameUpdate could observe it. Move frameUpdate() to after fireFrameReadyEvent() so such changes are synced and applied the same frame. Co-authored-by: Martin Valigursky <mvaligursky@snapchat.com>
Configuration menu - View commit details
-
Copy full SHA for 9cc0291 - Browse repository at this point
Copy the full SHA 9cc0291View commit details -
Martin Valigursky committed
Jun 3, 2026 Configuration menu - View commit details
-
Copy full SHA for 3f52bb8 - Browse repository at this point
Copy the full SHA 3f52bb8View commit details
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff v2.19.1...v2.19.2