{ "$schema": "https://raw.githubusercontent.com/guitaripod/wwdc-sessions/master/schema/session.schema.json", "schemaVersion": 1, "id": "wwdc2026-320", "event": "wwdc2026", "eventName": "WWDC26", "year": 2026, "eventContentId": 320, "title": "Explore immersive website environments in visionOS", "description": "Transport your website’s visitors into virtual environments in Apple Vision Pro using the new Immersive API in JavaScript. Explore how to request immersive transitions from an inline model element, create compelling immersive experiences using features like video docking, and optimize performance for rich, real-world-scale experiences — all with just a few lines of code running on your website.", "url": "https://developer.apple.com/videos/play/wwdc2026/320", "sosumiURL": "https://sosumi.ai/videos/play/wwdc2026/320", "type": "Video", "publishedAt": "2026-06-08T14:00:00-07:00", "platforms": [ "visionOS" ], "keywords": [], "topics": [ "Spatial Computing", "Safari & Web" ], "primaryTopic": "Safari & Web", "duration": 1149, "hasTranscript": true, "transcriptWordCount": 2966, "availableLanguages": [ "eng", "fra", "jpn", "kor", "por", "spa", "zho" ], "media": { "hls": "https://devstreaming-cdn.apple.com/videos/wwdc/2026/320/4/e1844891-477b-4612-ad8d-10e55bf395ba/cmaf.m3u8", "downloadHLS": "https://devstreaming-cdn.apple.com/videos/wwdc/2026/320/4/e1844891-477b-4612-ad8d-10e55bf395ba/cmaf-download.m3u8", "downloadSD": "https://devstreaming-cdn.apple.com/videos/wwdc/2026/320/4/e1844891-477b-4612-ad8d-10e55bf395ba/downloads/wwdc2026-320_sd.mp4", "downloadHD": "https://devstreaming-cdn.apple.com/videos/wwdc/2026/320/4/e1844891-477b-4612-ad8d-10e55bf395ba/downloads/wwdc2026-320_hd.mp4", "duration": 1149 }, "codeSnippets": [ { "title": "Basic model element", "language": "xml", "startTimeSeconds": 111, "code": "\n" }, { "title": "Model element with environment map", "language": "xml", "startTimeSeconds": 126, "code": "\n" }, { "title": "Adding the environment model on the page for inline preview", "language": "xml", "startTimeSeconds": 280, "code": "
\n\t\n\t\n
" }, { "title": "Reset the model entity transform", "language": "javascript", "startTimeSeconds": 314, "code": "const theater = document.getElementById(\"theater\");\n\nasync function updateModelTransform() {\n\t// Make sure the model is loaded\n\tawait theater.ready;\n\t// Create a transform matrix\n\tconst identity = new DOMMatrix();\n\t// Apply the transform matrix to the model\n\ttheater.entityTransform = identity;\n}\n\nupdateModelTransform();" }, { "title": "Translate the model down", "language": "javascript", "startTimeSeconds": 342, "code": "const theater = document.getElementById(\"theater\");\n\nasync function updateModelTransform() {\n\t// Make sure the model is loaded\n\tawait theater.ready;\n\t// Create a transform matrix\n\tconst transform = new DOMMatrix();\n\t// Translate model down, for eye level preview\n\ttransform.translateSelf(\n\t\t0, \t\t\t// x\n\t\t-1.0, \t// y\n\t\t0 \t\t\t// z\n\t);\n\t// Apply the transform matrix to the model\n\ttheater.entityTransform = transform;\n}\n\nupdateModelTransform();" }, { "title": "Build the seat transform", "language": "javascript", "startTimeSeconds": 400, "code": "function buildTransform(seat) {\n\tconst transform = new DOMMatrix();\n\tconst { x, y, z, ry } = seat;\n\t// Rotate and translate the model to match \n // the seat's origin and orientation\n\ttransform.rotateSelf(0, -ry, 0);\n\ttransform.translateSelf(-x, -y, -z);\n\t// Translate the model down, for eye level preview\n\ttransform.translateSelf(0, -1.0, 0);\n\treturn transform;\n}" }, { "title": "Detect feature availability", "language": "javascript", "startTimeSeconds": 436, "code": "if (document.immersiveEnabled) {\n\timmersiveButton.hidden = false;\n}" }, { "title": "Request the immersive transition on the model", "language": "javascript", "startTimeSeconds": 454, "code": "immersiveButton.addEventListener(\"click\", async () => {\n\tawait model.requestImmersive();\n});" }, { "title": "Build immersive transform", "language": "javascript", "startTimeSeconds": 504, "code": "function buildTransform(seat, immersive) {\n\tconst transform = new DOMMatrix();\n\t// [...] Seat transform logic\n\tif (immersive) {\n\t\t// Rotate to the left\n\t\ttransform.rotateSelf(\n\t\t\t0,\t\t// x\n\t\t\t45,\t\t// y\n\t\t\t0\t\t\t// z\n\t\t);\n\t} else {\n\t\t// [...] Eye level translation\n\t}\n\treturn transform;\n}" }, { "title": "Update the entity transform and the layout on immersive state updates", "language": "javascript", "startTimeSeconds": 541, "code": "theater.addEventListener(\"immersivechange\", () => {\n\tconst isImmersive = !!document.immersiveElement;\n\tconst transform = buildTransform(isImmersive, currentSeat);\n\ttheater.entityTransform = transform;\n document.body.classList.toggle(\"immersive\", isImmersive);\n});" }, { "title": "Hide the inline preview", "language": "xml", "startTimeSeconds": 653, "code": "\n" }, { "title": "Request an immersive transition on the escape room model", "language": "javascript", "startTimeSeconds": 685, "code": "const enterButton = document.getElementById(\"enterButton\");\nconst escapeRoom = document.getElementById(\"escapeRoom\");\n\nenterButton.addEventListener(\"click\", () => {\n await escapeRoom.requestImmersive();\n});" }, { "title": "Handle the request result and show a loading animation", "language": "javascript", "startTimeSeconds": 712, "code": "enterButton.addEventListener(\"click\", async () => {\n\tshowLoadingAnimation(); \n\ttry {\n\t\tawait escapeRoom.requestImmersive();\n\t} catch (error) {\n\t\tconsole.log(error);\n\t} finally {\n\t\thideLoadingAnimation();\n\t}\n});" }, { "title": "Dock the video in the environment with the fullscreen API", "language": "javascript", "startTimeSeconds": 796, "code": "const trailerVideo = document.getElementById(\"trailerVideo\");\nconst demoButton = document.getElementById(\"demoButton\");\n\ndemoButton.addEventListener(\"click\", async () => {\n\tawait trailerVideo.requestFullscreen();\n});" }, { "title": "Play the model animation", "language": "javascript", "startTimeSeconds": 841, "code": "const trailerVideo = document.getElementById(\"trailerVideo\");\nconst escapeRoom = document.getElementById(\"escapeRoom\");\n\ntrailerVideo.addEventListener(\"ended\", async () => {\n\tawait document.exitFullscreen();\n\tescapeRoom.play();\n});" }, { "title": "Compress your USDZ with usdcrush", "language": "bash", "startTimeSeconds": 998, "code": "usdcrush model.usdz -o optimized.usdz" } ], "resources": [ { "title": "Download - Immersive model add-on for Blender", "url": "https://developer.apple.com/download/files/web-env-blender-plugin.zip", "type": "download", "description": "Use this Blender extension to help you create your own 3D environment and add video docking, lightspill and other visionOS features.", "sosumiURL": "https://sosumi.ai/download/files/web-env-blender-plugin.zip" }, { "title": "WebKit.org - Theater Ticket Sales immersive website environment demo for Apple Vision Pro", "url": "https://webkit.org/demos/model-demos/ticket-sales.html", "type": "documentation", "description": "Test drive an example ticket sales website where you can explore the view of the stage from any seat you choose. Then, on Apple Vision Pro explore the view from inside the theater with the immersive website experience. Use Web Inspector to explore the code that makes this experience possible with Safari 27.0 in visionOS." }, { "title": "WebKit.org - Escape Game immersive website demo for Apple Vision Pro", "url": "https://webkit.org/demos/model-demos/escape-room.html", "type": "documentation", "description": "An immersive website environment demo featuring an example marketing website for an escape game app. Explore the demo in Apple Vision Pro and use Web Inspector to see how the Immersive API is used to create the experience." }, { "title": "GitHub: Spatial Backdrop explainer", "url": "https://github.com/WebKit/explainers/tree/main/spatial-backdrop", "type": "documentation", "description": "Operating systems on virtual reality devices have the capability of displaying virtual environments behind the windows and volumes of the various applications running on the device including its web browsers. This new link type enables Websites to change this virtual environment to one that is specified by the web page." }, { "title": "WebKit.org – Report issues to the WebKit open-source project", "url": "https://bugs.webkit.org", "type": "documentation", "description": "Bug tracking for WebKit open source project" }, { "title": "Submit feedback", "url": "http://feedbackassistant.apple.com", "type": "documentation", "description": null } ], "path": "sessions/wwdc2026/320-explore-immersive-website-environments-in-visionos/", "files": { "metadata": "sessions/wwdc2026/320-explore-immersive-website-environments-in-visionos/metadata.json", "readme": "sessions/wwdc2026/320-explore-immersive-website-environments-in-visionos/README.md", "transcript": "sessions/wwdc2026/320-explore-immersive-website-environments-in-visionos/transcript.md", "transcriptJSON": "sessions/wwdc2026/320-explore-immersive-website-environments-in-visionos/transcript.json" } }