Joshua Opolko

Walkable 1:1 Scale Pavilion: Architectural Daylighting in Three.js WebXR

By Joshua Opolko · June 2026

7:00 AM Drag to move the sun
What this is: a contemporary concrete-and-glass pavilion at true 1:1 metric scale, rendered in Three.js r169 directly in your browser. The building is 12 m × 8 m with a 3.2 m ceiling, a fully glazed south facade with steel mullions, a cantilevered roof overhang, and a reflecting pool at the entrance. Drag the sun slider to sweep shadows across the polished concrete floor from dawn to dusk. On desktop: drag to orbit, scroll to zoom. On Meta Quest: tap Enter VR.

Why 1:1 scale changes everything

Architectural drawings and 3D renders both suffer from the same perceptual failure: you look at them from the outside. A floor plan tells you a room is 12 by 8 metres, but that measurement carries no weight until you are standing inside it. A render shows you a space from a fixed camera angle, and you have no felt sense of how big the ceiling is relative to your own height.

At 1:1 scale in VR the ceiling in this demo is 3.2 metres above your head. Not above a miniature avatar. Above your head. The roof overhang reads as an overhang because you are standing under it. The glazed facade is full-height glass because you are a person standing in front of it. These are spatial relationships that humans assess through embodied experience, not through numbers on a drawing, and WebXR makes them accessible directly in a browser without an install.

For architectural design review, the implications are significant. Space-planning decisions that take multiple revision rounds in 2D become immediately apparent in a 1:1 walkthrough. A corridor that measures adequately on a plan can feel wrong the moment you are standing in it. A window sill height, a ceiling soffit, a stair headroom clearance: all of these self-reveal in VR in ways they simply do not on screen.

The daylighting study

The sun slider is the central feature of this demo. It drives a DirectionalLight whose position is calculated from solar azimuth and elevation equations for a northern-hemisphere mid-latitude site. Moving the slider from 6 AM to 8 PM rotates the sun from east to west through the southern sky, and three things happen simultaneously: shadow length changes (long at dawn and dusk, shortest at noon), shadow angle rotates (from northwest-pointing at dawn to due-north at noon to northeast-pointing at dusk), and light colour temperature shifts (warm amber at the edges of the day, cooler and brighter toward noon).

These are not abstract parameters. They are what a client experiences when they live in the building. The overhang is sized so that noon summer sun lands at the threshold of the glass and does not penetrate to the back wall, while lower-angle morning and afternoon sun reaches deep into the plan. Showing this in a browser, at human scale, in a minute of interaction, is something that traditionally requires Revit with Autodesk Insight or Rhinoceros with Ladybug installed, a rendered animation file, and a meeting to walk through it. It runs here in a script tag.

Material setup (no textures)

Every surface uses MeshStandardMaterial with only color, roughness, and metalness. No texture images, no UV maps, no external assets beyond Three.js itself. The polished concrete floor (roughness 0.38, metalness 0.04) catches long specular streaks from the sun at low angles, which is physically correct and which is what makes shadow lines read so clearly on it. Raw concrete walls (roughness 0.88) absorb rather than redirect light. The glazing (roughness 0.03, transparent, opacity 0.20) lets the exterior ground plane and sky be visible through it without obscuring the interior.

Building the sun study in Three.js

const sun = new THREE.DirectionalLight(0xfff5e0, 3.5);
sun.castShadow = true;
sun.shadow.mapSize.setScalar(2048);
scene.add(sun);
scene.add(sun.target);
sun.target.position.set(6, 0, 4); // centre of floor plan

function setSunTime(hour) {
  const t = (hour - 6) / 14;            // 0 at 6 AM, 1 at 8 PM
  const elev = Math.max(0.04, Math.sin(t * Math.PI)) * (68 * Math.PI / 180);
  const azim = (t - 0.5) * Math.PI;     // -PI/2 east, 0 south, +PI/2 west

  sun.position.set(
    6  - Math.sin(azim) * Math.cos(elev) * 60,
    Math.sin(elev) * 60,
    4  - Math.cos(azim) * Math.cos(elev) * 60
  );

  // Warm amber at edges, cool white at noon
  const warmth = 1 - Math.sin(t * Math.PI);
  sun.color.setRGB(1.0, 1.0 - warmth * 0.14, 1.0 - warmth * 0.32);
  sun.intensity = Math.max(0.2, Math.sin(t * Math.PI) * 3.8 + 0.4);
}

document.getElementById('sun-slider').addEventListener('input', e => {
  setSunTime(parseFloat(e.target.value));
});

Performance on Meta Quest browser

The Quest browser WebXR target is 72 Hz at 1832 × 1920 per eye. Shadow maps are the main budget item here. The scene uses a single shadow-casting DirectionalLight with a 2048 × 2048 PCFSoft map and a tightly fitted shadow frustum (20 m × 20 m, near 1, far 80). All other lights are non-shadow-casting hemisphere fill. This keeps the shadow pass to one draw call and runs stably on Quest 3. On Quest 2, drop the shadow map to 1024 if needed.

Replacing the pavilion with your own model

Swap the box geometry for GLTFLoader to load exports from SketchUp, Revit, or ArchiCAD. The web-ifc-three library adds native IFC loading. The sun study code is geometry-agnostic: the setSunTime() function works against any scene once the shadow-casting light and its target are placed correctly. See the architectural visualization guide for the full pipeline from BIM software to browser-based WebXR review session.

Frequently asked questions

Does this work on Meta Quest?

Yes. Open this page in Meta Quest Browser on Quest 2, 3, or Pro. Tap the Enter VR button at the bottom right of the demo. The pavilion appears at true 1:1 scale. Orbit to walk around and through the building.

How does the sun slider work technically?

The slider value (6 to 20, representing 6 AM to 8 PM) drives solar azimuth and elevation calculations. The DirectionalLight position updates every time the slider moves, which re-triggers shadow map rendering for that frame. No animation loop is needed for the slider; the render loop runs continuously regardless.

Can I load my own floor plan?

Yes via GLTFLoader (SketchUp, Revit, ArchiCAD exports) or IFCLoader from web-ifc-three for native IFC. The sun study and WebXR code is geometry-agnostic.

Why does 1:1 scale matter for architecture?

At true scale, spatial decisions that are ambiguous on a floor plan become immediately apparent: whether a room feels large or cramped, whether a ceiling height is generous or oppressive, whether an overhang is long enough to do its job. These cannot be reliably perceived from drawings or renders. They require being inside the space at human scale.

Written by Joshua Opolko, who builds browser-based XR and writes about self-hosting, AI, and immersive technology at joshuaopolko.com. Pavilion dimensions follow a compact but generous single-storey proportion; furniture scale is realistic for the space. June 2026.