Skip to content

v4.49.0

Choose a tag to compare

@github-actions github-actions released this 29 Sep 23:20
· 176 commits to main since this release
7f92de3

v4.49.0 — 2026-09-29

Added

  • Demo (Android): Rerun Record captures a dense coloured point cloud on phones with ARCore's Depth API (e.g. Pixel 9): raw depth is kept where ARCore is confident, back-projected and fused into 2 cm surfels, saved in the .svscan file as dense/points.bin (format v2, 12 bytes a point), drawn by the replay, and exported to .ply (with normals), .glb and .rrd (world/dense). Phones without depth record exactly as before, and older .svscan files still open.
  • Demo: HD pack (Android). The Model Viewer gains a full-resolution Flight Helmet (Khronos, CC0, 48 MB) that downloads once on Wi-Fi after install, resumes if interrupted and is checked against its SHA-256 before use. The bundled Damaged Helmet shows instantly in its place, and a pill tracks the download until the viewer switches to the HD model. About → App gets an "HD scenes" row with Download now and Remove.
  • iOS demo — HD pack: heavy demo assets now ship outside the App Store build. They are downloaded once, verified by SHA-256 and kept in Application Support (excluded from iCloud backup) from the content-addressed hd-pack-v1 GitHub Release, listed in the bundled assets/hd-pack/ios.json manifest. The download starts on its own only on an unmetered network. On cellular or Low Data Mode, nothing downloads until the user taps "Download now", which states the size first. The About tab gets an "HD scenes" row (size, Downloaded / Download now / Remove), and a scene that needs an HD asset shows its bundled stand-in right away with a pill that names the HD model it is fetching ("Flight Helmet · downloading 34 %"), held on "loading" until the HD model is actually drawn, then swaps it in. First asset: the Khronos Flight Helmet (CC0, 2K textures, 52 MB) in the Model Viewer, with the Damaged Helmet as its stand-in. tools/convert-usdz.sh gains an opt-in --transmission-as-alpha flag that maps glTF KHR_materials_transmission to alpha-blended opacity, because UsdPreviewSurface has no transmission and glass would otherwise render opaque.
  • Demo app — Cosmos: a new demo of four procedural, real-time space scenes lit only by their own HDR light and bloom: a four-arm spiral galaxy of 60,000 stars with dark dust lanes, on screen within a second of opening, a plasma star with a noise-shaded surface and magnetic loops, a looping burst of charged-particle tracks, and a vortex flow field with travelling pulses. Pick a scene from the dock or let the tour cycle them. Four new demo materials (cosmos_sprite, cosmos_ribbon, cosmos_plasma, cosmos_dust) show how to draw glowing points and strokes as camera-facing geometry, because POINTS and LINES draw one pixel wide on mobile.
  • iOS demo: Cosmos. The iOS demo app now has the four Cosmos scenes (galaxy, star, particle burst, vortex flow) with the same captions and dock as Android. SceneViewSwift gains SceneView.bloom(_:) with BloomOptions (strength, levels, resolution, threshold, thresholdLevel), named after Android's bloom options; it needs iOS / macOS 26+ and does nothing on earlier versions.
  • iOS demo — Museum & Space: the Model Viewer's picker gets a "Museum & Space" section with four HD pack models, at parity with Android: the Smithsonian Apollo 11 Command Module and Apollo 11 Interior (CC0), the Smithsonian Woolly Mammoth skeleton (CC0) and NASA's Perseverance Rover (NASA media guidelines, insignia removed). None ships in the App Store build, and none downloads on its own: the HD pack now downloads per model. Only the Flight Helmet (52 MB) is still prefetched on Wi-Fi. A Museum model shows its thumbnail and a pill with its own size ("Apollo 11 Interior · download 38 MB"). A tap opens a dialog that names the model, states its size and, on cellular, warns that it uses mobile data. Once downloaded, the model appears at its real-world size, read from a new optional scale field of the shared assets/hd-pack/ios.json manifest. Perseverance opens still: its 23 mechanism clips stay under Animate, paused. These models are not offered in AR yet. Their credits appear in the app's Credits screen, read from the manifest. The About row now covers the Flight Helmet plus the models you downloaded. A slow HD load no longer lands over a model picked after it. A demo header whose status pill is too long for one row puts the pill on a second row instead of squeezing the demo title to a single letter, and keeps that layout while the download counts up.
  • Demo: "Museum & Space" in the Model Viewer (Android). Four real-world scans join the HD pack: the Apollo 11 Command Module and its cut-away interior (Smithsonian, CC0), a woolly mammoth skeleton (Smithsonian, CC0) and the Perseverance rover (NASA/JPL-Caltech, insignia removed). Each opens at its real size, its thumbnail stands on the stage until the file is on the device, and each model downloads on its own: tapping its pill shows that file's size (with a mobile-data warning on a metered network), and the pill then tracks that file alone — "queued" while another one downloads. The Wi-Fi prefetch stays limited to the Flight Helmet, and picking another model while a slow load runs no longer lets the stale one land on stage. The shelf opens under Studio lighting (a lighting the user picks stays), switching between two scans releases the first before the second is read, and Perseverance holds its pose instead of playing its 23 animations at once. Credits reach About → Credits from the manifest.
  • iOS demo app: Real-World Scan, Models and Explore's hero now match Android. The raccoon stump scan Android opens from "Real-World Scan" now opens on iPhone too, with the same copy, point counter and "Points drawn" control. iPhone has no splat renderer yet, so it draws each captured point as a small solid dot and says so on screen ("Phone capture · 233 808 points drawn as dots · 3.2 MB"). The Model Viewer card is now "Models", with Android's subtitle and position. Explore opens on a large "Trending" card with the model's picture, its source and a "View in 3D" button. The source picker is a segmented control. Cosmos is on the home screen with Android's card. Also fixed: the Explore navigation bar no longer turns black in light mode when a dark picture scrolls under it. Light and dark.

Changed

  • CI (App Store): the latest release now reaches Apple on its own. A new app-store-catch-up.yml probes App Store Connect every 3 hours from an ubuntu runner and submits the latest GitHub release as soon as no other iOS version is in review. It reuses that release's TestFlight build, and only dispatches a macOS rebuild when no build exists. A release that has to wait behind another version in review now ends green with a notice instead of a red run. An opt-in supersede dispatch input withdraws an older version from review so the latest release can replace it. A release that Apple rejected or that was withdrawn from review by hand is never resubmitted automatically.
  • Demo app (debug builds): a debug build of the Android demo is now its own app, installed next to the Play Store one instead of replacing it: application id io.github.sceneview.demo.qa, version suffixed -qa, launcher label "SV QA" and the SceneView icon with an amber QA badge (themed icon included). QA scripts, Maestro flows and instrumentation tests now target that id. The debug APK attached to GitHub Releases is unchanged — still io.github.sceneview.demo, "SceneView" — because build-apks.yml builds it with the new -PdemoPlainDebug=true Gradle property.
  • Repository: 381 MiB of stale screenshots and QA captures that nothing builds, loads or links are gone from the tree (docs/ux/captures, tools/qa-screenshots, docs/site-screenshots, samples/screenshots/android, the root qa-screenshots/ and three duplicate docs images). A checkout drops from 1.19 GiB to 0.82 GiB. No model, environment, video, golden or store graphic changed, and the removed files stay in git history.
  • Demo app home: cards are pictures first. Each catalogue card is now a square picture that melts into a frosted caption made from its own blurred image, instead of a picture stacked on a white text box. Cards side by side end level, on the home grid and in Explore's "Try a demo" row, without cutting any text. The Featured shelf becomes a swipeable row of tall 4:5 cards, with a full-bleed picture, a caption floating on it and a light parallax. Light and dark.
  • iOS demo: porsche_911_turbo.usdz was a byte-identical copy of porsche_911.usdz. The "Porsche Turbo" catalogue entry now loads the single shipped file, and the app bundle is 11.8 MiB lighter. The bundled Credits sheet lists the model once, under Karol Miklas, instead of a second row that credited Lionsharp Studios for the same file.
  • Repository: the demo apps' 3D models and HDR environments (Android, TV, iOS) and the website's platform models move out of git into the assets-v1 GitHub Release, listed with their sha256 in assets/manifest.json. bash tools/fetch-assets.sh downloads them once into a shared cache and puts them back in place; the Android, TV and iOS demo builds, the website deploy and every CI workflow that builds them run it on their own. A checkout shrinks by about 544 MiB. The store apps and the website ship byte-identical files. Building the demos or the site now needs bash, python3 and curl (Windows: WSL), and a model that is in a managed folder but not registered in the manifest fails the build instead of shipping from one machine only. The CREDITS drift check (generate-credits.py --check), which had run in no workflow since #3244, is back in CI.
  • iOS demo app home: cards are pictures first, as on Android. Each catalogue card is a square picture that melts into a frosted caption made from its own blurred image. Cards side by side end level, on the home grid and in Explore's new "Try a demo" row. The Featured section becomes a swipeable shelf of tall 4:5 cards, with a full-bleed picture, a floating caption and a light parallax. Light and dark.
  • iOS demo — Model Viewer at parity with Android:
    • Picker cards: the Models picker now shows the same cards as Android: the model's render over its name and a short description ("Columbia, as flown in 1969 · HD"), on a surface card with a hairline. The model on screen is outlined, and the two cards in a row share one height. The text follows the system text size, and long names wrap instead of being cut off.
    • Dock order: the dock now reads Models, Lighting, Animate, Recenter, as on Android.
    • Lighting: Museum & Space models open under the neutral Studio lighting instead of the green-tinted Chinese Garden, as long as the lighting is still the default. Going back to another model restores the garden only if the app switched to Studio itself; a lighting you picked stays. "Reset lighting" returns to the lighting the model opens under.
  • iOS demo — Model Viewer: the model picker shows each model on a transparent background over the card, as on Android, in light and dark. Shared models reuse Android's own transparent renders; Cyberpunk Hovercar and Butterfly, which only iOS ships, are rendered the same way. The HD poster now uses the same 5:4 frame as Android. Image Planes keeps its opaque square pictures under their own names. The Woolly Mammoth and the Perseverance rover open three-quarter, as on Android: the iOS camera already opens at that angle, and a test now holds it within 10° of Android's turn.
  • iOS demo: Cosmos moves like Android. The ribbon dashes of the star, burst and flow scenes now travel, stars and sparks twinkle, and the star's plasma surface churns instead of only turning — all without a custom shader. The churn bakes half-size frames in the background and pauses in Low Power Mode or when the device runs hot. The Flow scene turns a quarter in landscape like Android, and the star gets more cell contrast and a wider blue limb halo. On macOS, demos now open in a sheet large enough to use instead of a thin strip.
  • iOS demo — Model Viewer: models open in the same pose and at the same size as on Android. The camera starts in front of the model and 12° above it, not 36° to the side and 30° above, and the fit is tighter, so a model fills the stage as much as it does on Android. The Woolly Mammoth and the Perseverance rover turn -30° on their own to show a three-quarter view, as on Android. So does the Hovercar, which is iOS-only. Recenter returns to this pose. The HD preview no longer stretches across an iPad screen.
  • iOS demo: the Home reads like any app under its 3D header, as on Android (#4188). The Featured shelf and the large picture cards gave way to the same list Android shows: compact grey rows with a small thumbnail, a title and a one-line description, grouped by section, with the New and Updated tags beside the title. On iPad the rows sit in two columns. The 3D header is unchanged, every demo keeps its place and its section, and the tags now stay visible in dark mode.

Fixed

  • iOS demo app: Materials and Lighting now open on the same scene as Android. Materials shows Android's wall of nine labelled spheres: chrome, gold, copper, aluminum, ceramic, car paint with a clear coat, velvet with sheen, crystal and a neon glow. The camera slowly sweeps across them, and you tap a sphere to zoom in on it and tune its metallic and roughness. It needs no network and no Sketchfab key, so the "Mosquito in Amber" offline stand-in is gone. The crystal sphere is labelled "transparency" on iPhone because RealityKit has no refraction. Lighting now stands the Damaged Helmet on a slate floor with the chrome and matte probe balls at its feet, framed on the helmet rather than on the floor, and circles it slowly (Animate pauses the orbit). The Home screen no longer ranks Cosmos and Augmented Faces at the same position. Light and dark.
  • iOS demo: the home header is the same live dusk flight as on Android (#3907). The rounded card with a studio-lit helmet is gone: a full-bleed stage now runs from the top of the display, with the same valley of flat-shaded ridges streaming under a swaying, rolling camera, the low sun, the fog that dissolves the far ridges into the dusk sky, and the Model Viewer's helmet turning beside the camera. It uses the same flight path, easing, entrance, tilt response, parallax and scrim as Android. The header reads white over the sky and returns to the page colours once scrolled. Once scrolled away the 3D view goes idle, and under Reduce Motion it stops animating once the frame is posed.
  • The Lighting demos' stage now looks infinite, and the Sun rig's day actually runs (#4072). With Animate on, the Sun rig's clock now moves from dawn to dusk, so the sun crosses the sky and the hour label counts it. The three skies are loaded one at a time once the stage is up, so opening the Sun rig is no slower than before and the sky changes without a hitch. The floor on the Sun, Studio, Image and Lab stages no longer shows its edges at any zoom: it fades into a ground tone taken from the sky picture and meets it at a horizon, or into the stage colour when the sky is hidden. Shadows stay as sharp as before.
  • Demo · Your Room, as a Dollhouse: the miniature now stands 40 to 60 cm long instead of at most 35 cm (a 4 m room opens at 1:8, not 1:12), its points are drawn about twice as large and the path the phone walked reads as a clear line, about twice as thick as the points. The Real size toggle still shows the room at 1:1.
  • Demo app: "Your Room, as a Dollhouse" no longer freezes, says which recording stands, and Reset really resets (#4075). Going from AR to the 3D view and back reused a placement state the first AR view had dismissed, so the room never stood again; each AR view now takes a fresh one. Reset lifts the room and waits a moment before standing it where you aim, back at 1:12, instead of putting it straight back. The recording on the table is named, with its date, and a tap lists every kept recording to stand another. A recording that kept no floor, wall or table says so and offers to record again, instead of standing an empty plinth. The plinth now has a thickness and a contact shadow, and the surfaces are drawn in solid colour where there is no photo. The Real size button keeps its name and lights up while the room stands at real size, so it always agrees with the scale shown above the dock (it read "Miniature", lit, over "Real size"). At real size the room no longer stands centred half a metre from the camera, its walls and floor cutting through the view: its near side sits where the miniature stood and it reaches away from you, turned so the side you started recording from faces you.
  • Demo (Android): Rerun AR Replay's Record mode records the room again on a real phone. The recorder's first feature-point and plane sample was never due (a Long.MIN_VALUE timestamp overflowed), so a scan kept the camera path but no point and no plane, and its .ply export had zero vertices.
  • Demo (Android): the replay's photo-coloured feature points draw again (#4095). Their colour atlas was sampled upside down, on rows it never wrote, so the whole layer was transparent.
  • arsceneview: PlaneRendererV2 builds its depth-driven plane mesh again. The same Long.MIN_VALUE overflow kept the depth path from ever running, so V2 always fell back to the flat polygon. It only asks ARCore for a depth image when the session's effective depth mode is AUTOMATIC, and a failed acquisition keeps the flat polygon instead of skipping the plane update.
  • Demo app: the Park is a park, on Android and iOS (#4103). It used to show four tree scans at unrelated sizes in a grey studio under a softbox. It now shows a pair of oaks, a bench, a street lamp and a fern at one consistent scale, standing on a lawn in Poly Haven's "Chinese Garden". The four models are a 12.5 MB download instead of 63 MB. The lawn renders the same natural green on both platforms. On iOS, models now stand on the ground (before, a model's position replaced the offset that grounds it), the screen is titled "Park Scene" as on Android, the camera frames the whole park even when the oaks stream in last (without ever snapping back a camera the user has orbited or zoomed), and the leaves of streamed models are cut out instead of drawn as pale translucent cards: RealityKit read their opacity from the wrong texture channel. Offline on Android, the stand-in for the oaks now faces the camera. The Nile statue, which no screen has shown since the Scene Gallery left Android, is no longer credited there. The iOS viewer's environments are named after what they show, like Android's: "Studio" and "Interior" instead of "Studio Warm" and "Studio", and "Seascape" instead of "Sunset" for the cloudy sky over the sea (an iOS-only tile: Android's "Sunset" is a different HDR). "Chinese Garden" is added. As on Android, it comes first and is the environment of a first launch, and Studio comes before Interior. On iOS the Credits sheet groups the Scene Gallery models under "Scene Gallery".
  • Docs: structured data lists the real ARCore and Kotlin versions. The schema.org block on the docs site advertised ARCore 1.54.0 and Kotlin 2.1.21; it now says ARCore 1.56.0 and Kotlin 2.4.20, the versions the SDK builds against.
  • Demo (Android): A dense Rerun scan now shows the same point count in the "Your sessions" list and in its replay as the scan HUD showed while recording (e.g. 186k, not 12k). The dense cloud was always saved in full; the list and the replay were counting ARCore's sparse feature points, which stop at 12,000. Scans saved before this fix read the right number from their file.
  • Demo app: Explore and the Lighting sheet match the rest of the app (#4135). Explore opens with a real header (back icon and title) instead of a bare "← Showcase" text link, and the viewer's Lighting sheet says "Brightness" instead of "IBL intensity".
  • Demo app: opening Models from the Home hero stalls much less (#4143). When the user left Home before the hero finished loading, its engine kept loading (the HDR sky, the terrain material, the helmet textures, the terrain upload) and competed with the viewer for the GPU, which held the viewer on "Loading model…" and could raise "isn't responding". The hero now starts and loads only while Home is on screen, packs the terrain off the main thread, and SceneRenderer no longer waits a second time for a swap chain it has already released. On the emulator, tapping Open right away now shows the model in 13–22 s instead of 18–49 s.
  • CI (Device QA): the Android Maestro leg now sets up JDK 22. It rebuilds a keyed demo APK on the emulator runner, and without the toolchain Gradle failed before the first flow (Cannot find a Java installation … languageVersion=22). The leg is advisory, so those runs still showed green.
  • CI: publishing a data release (hd-pack-v1, assets-v1) no longer posts a release announcement on Discord or redeploys the website from that tag's commit. Only v* SDK releases trigger them.
  • Docs: version numbers match what the SDK builds against. AGENTS.md now quotes SceneView 4.48.0 and Kotlin 2.4.20 instead of 4.37.0 and 2.4.10. The Android XR pages, llms.txt and the iOS cheatsheet now give androidx.xr.arcore as 1.0.0-beta02, the version the SDK pins, instead of alpha builds. llms-full.txt names the right Compose and Android versions. llms.txt no longer says sceneview-compose is unpublished: it has been on Maven Central since 4.27.0.
  • Docs: the Android XR snippets compile against the Jetpack XR beta SDK they cite. android-xr.md and android-xr-emulator.md now import SpatialPanel, SubspaceModifier and LocalSpatialCapabilities from their real packages. Passthrough uses preferredPassthroughOpacity. glTF models load with GltfModel.create before being wrapped in GltfModelEntity.create, and the model is closed when the composable leaves. Session.create is handled as the suspend call it is, returning a SessionCreateResult. Taps on ARSceneView go through onGestureListener. The manifest example declares the real android.software.xr.api.spatial feature instead of a non-existent head-tracking one. The phone-ARCore-in-a-panel approach is flagged as untested on a headset, and points headset users to XrHandNode / XrFaceNode. The @XrPreviewApi opt-in message and the XR KDoc no longer quote 1.0.0-alpha14. AGENTS.md defers to llms.txt for version numbers instead of repeating them.
  • Website: every 3D model the site serves is credited on a new /credits.html page. The page lists each model's author, licence and source link, with its thumbnail. generate-credits.py generates it from assets/catalog.json, and its --check (run in CI and before each site deploy) fails when the page drifts from the catalog. The footer on every page now links to it. The catalog gains a shippedAs field for the site's file names, the missing authors from Sketchfab and Khronos metadata, and a corrected licence for AntiqueCamera (CC0-1.0).
  • Demo app: the loading cover now hands over to a demo's first rendered frame in 150 ms instead of 350 ms (new motion-handover token). Tracing showed the cover already lifts within ~30 ms of Filament finishing frame 1; the remaining wait on the emulator is frame 1's first shader compile, not the cover. (#4160)
  • iOS demo app home and Explore now match Android. Cards show the same "New" and "Updated" chips as Android, driven by the same version declarations on each demo. "Browse online models" is a full-width row under the Featured shelf, as on Android. Materials is back in its section on builds that can stream its model. Explore follows Android's order: search, the "Trending in 3D" rail, "Browse by source" with the Animated filter, then "Try a demo". Light and dark.
  • Demo app: Cosmos no longer pops brighter about half a second after it opens. Bloom and the galaxy's dust lanes, which join only once the first frame is on screen, now ramp up over 700 ms (eased out), so the scene ignites instead. (#4160)
  • iOS / macOS demo: the demo app builds again on every Apple platform. Cosmos now declares the version it shipped in, so the "Collate iOS demos" freshness check passes. Its glow and frame clock also compile for macOS: an AppKit import, a non-failable linear tint, and a display link that comes from the screen.
  • Demo — Museum & Space follow-ups. Leaving an HD scan for a bundled model no longer shows a black stage while the next model loads; a paused animation stays paused when the HD file replaces its stand-in; an opened file or a Surprise pick no longer switches the lighting to Studio; the lighting, the Animate action and the AR action now change with the model on screen, not at the pick, so a scan still shown while the next model loads keeps its Studio light instead of flashing yellow, and a scan's picture stays up until the scan is drawn; one failed model download no longer marks the whole HD pack "Failed" in About; picker card titles wrap to two lines ("Apollo 11 Command Module"); after "Open with SceneView", picking another model retitles the screen and sends that model to AR. (#4171)
  • ModelNode — an animated model no longer vanishes when another model is destroyed after it was added. Every gltfio Animator.applyAnimation commits a TransformManager transaction, and a commit re-sorts the packed hierarchy — but only when a destroy or a reparent has broken its order, not on every frame. That re-sort reindexed the node's cached transform handle; its transform then went to one of the model's own meshes and a skinned model rendered as nothing. Until the order is repaired, nodes now resolve their handles fresh instead of caching them, so a commit from anywhere — ModelNode, a direct applyAnimation or applyCrossFade, app code — is safe; the frame loop repairs the order once at the top of the next frame, and caching resumes. (#4171)
  • iOS demo: Cosmos Flow survives a rotation. Turning the device on the Flow scene no longer blanks the field and replays its reveal: the new orientation is built while the old one stays on screen, then swapped in without restarting the scene clock or the tour. The star's background plasma bake can no longer run twice at once after a reset, the power and thermal state are read from their notifications instead of on every frame, and the macOS-only sheet size floor no longer applies to other platforms.
  • Android demo: Museum & Space models look as clean as on iOS (#4179). "Reset lighting" with an Apollo 11, Woolly Mammoth or Perseverance scan on stage now returns to Studio, the lighting the model opens under, instead of Chinese Garden, whose warm sun gave the white scans a yellow halo and a sepia cast. With the environment hidden, every model in the viewer now stands on the navy stage colour instead of pure black, as on iOS, in light and dark.
  • Android demo: picking a model in the Model Viewer frames it from its own pose (#4179). Picking the Apollo 11 capsule flashed a full-screen close-up of it before its entrance, and the model picked after it arrived as a speck: the camera glided from the previous model's distance. Each model now opens on its own entrance.
  • iOS demo — Model Viewer: models fly in the way they do on Android. When a model opens, the camera starts further out, 24° to the side and a little higher, then glides to the resting view in 700 ms while the model rises into place. Recenter glides back from wherever you left the camera. Touching the model during the flight hands the camera to you at once, and Reduce Motion skips the flight. The Toy Car's cloth is copper velvet again, as on Android, instead of dull pink: its USDZ had lost the glTF sheen and base colour.
  • SceneViewSwift: a cameraPose(_:) write that moves the camera now takes it from the fit-to-bounds pass, as a drag does, so a pose animated frame by frame is no longer pulled back to the fit while the content's bounds settle. A contentID(_:) swap or a recenterCamera(_:) hands the camera back.
  • Android demo: the Home reads like any app under its 3D header (#4186). The tall Featured carousel and the large square picture cards gave way to one vertical list of compact grey rows: a small thumbnail, a title and a one-line description, grouped by section like a phone's settings, with the New and Updated tags beside the title. The 3D header is unchanged, every demo keeps its place and its section, and the list stays readable in light and dark and at large font sizes.
  • iOS demo — Model Viewer: models stand on the navy stage, as on Android, instead of in front of the Chinese Garden sky. The environment still lights the model; "Show environment" in the Lighting sheet draws it behind, stays on when you pick another environment, and Reset lighting turns it off again.