Joshua Opolko

Walkable 1:1 Scale Room: A Three.js WebXR Architecture Demo

By Joshua Opolko · June 24, 2026

What this is: a modern loft interior at true 1:1 metric scale, rendered in Three.js r169 directly in your browser via WebXR and WebGL. The room is 10 m × 14 m with a 4 m ceiling, a brick fireplace wall, three large windows, exposed timber beams, and a fully furnished living and dining space. On a Meta Quest, press Enter VR and teleport anywhere in the room. On desktop, drag to orbit.

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 10 by 14 metres, but that measurement carries no weight until you are standing inside it. A render shows you a room 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 4 metres above your head. Not above a miniature avatar. Above your head. The sofa is the right height to sit on. The window sills are at hip height. The dining table is exactly dining-table height. 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, and that only occasionally get caught in rendered flythrough videos, 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 lighting setup

The scene uses two competing light sources that create the warm/cool contrast visible across the room. Three pendant lights above the dining area emit warm tungsten light (approximately 2700K). The windows on the north face bring in a cooler daylight tone. The result is that objects facing the windows are cooler-toned and objects facing toward the fireplace and pendants are warmer, producing the same depth-creating contrast found in well-designed residential interiors and quality architectural photography.

A subtle trick with the pendant lights: the light source is placed at the position of the visible bulb mesh, and the mesh has a high emissiveIntensity. This means the visible globe is the source of the visible glow, which reads correctly to the eye. The fireplace uses the same principle: an orange PointLight sits inside the firebox with a randomised intensity offset each frame to simulate the flicker of live embers.

The environment uses Three.js RoomEnvironment with PMREMGenerator to create an image-based lighting map. This makes reflective surfaces, the polished concrete floor in particular, pick up correctly coloured reflections from their surroundings instead of reflecting a flat sky colour.

Material setup (no textures)

Every surface uses MeshStandardMaterial with only color, roughness, and metalness. No texture images, no UV maps, no external assets. The difference between concrete (roughness 0.52, metalness 0.06) and polished walnut (roughness 0.74, metalness 0) is real and visible, especially under the directional pendant lights which create distinct specular highlights on smoother surfaces. The polished floor at roughness 0.52 catches elongated warm highlight streaks from the pendant lights, the tell that separates a physically-modelled scene from flat-shaded geometry.

Building a walkable room in Three.js

// Warm pendant lights over dining table
[{ x: 3.2, z: 3.8 }, { x: 5.0, z: 4.6 }, { x: 6.8, z: 5.4 }].forEach(({ x, z }, i) => {
  // Visible glowing bulb
  const bulb = new THREE.Mesh(
    new THREE.SphereGeometry(0.055, 10, 8),
    new THREE.MeshStandardMaterial({
      color: 0xfffce0, emissive: 0xffd050, emissiveIntensity: 4.0
    })
  );
  bulb.position.set(x, 3.05, z);
  scene.add(bulb);
  // Point light at same position
  const pl = new THREE.PointLight(0xffc870, 2.8, 8, 2); // decay=2 = physically correct
  pl.position.set(x, 3.05, z);
  if (i === 1) pl.castShadow = true;   // one shadow caster keeps Quest perf stable
  scene.add(pl);
});

// Fireplace flicker in render loop
let tick = 0;
renderer.setAnimationLoop(() => {
  tick++;
  firePL.intensity = 1.8 + Math.sin(tick * 0.07) * 0.4 + Math.sin(tick * 0.19) * 0.25;
  renderer.render(scene, camera);
});

Window openings are created by building the back wall from panels around the gaps rather than cutting holes, since Three.js core does not support boolean subtraction. Each window has a dark glass pane (roughness 0.04, transparent: true, opacity 0.22) plus individual timber frame members for depth.

Performance on Meta Quest browser

The Quest browser WebXR target is 72 Hz at 1832 x 1920 per eye. The limiting factors for a scene like this are shadow map sampling and draw calls. To stay within budget: shadow casting is enabled on only one of the three pendant lights, the shadow map is 2048 x 2048 with PCFSoft filtering, and the directional window light handles the main hard shadows from furniture. On Quest 3 this runs at stable 72 Hz; on Quest 2, reducing the shadow map to 1024 keeps it smooth.

Replacing the room 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 WebXR session, VRButton, and teleport locomotion code in this demo is geometry-agnostic: add your floor geometry to the raycaster walkable array and the teleport works immediately. 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 room appears at true 1:1 scale. Point your controller at the floor and squeeze to teleport anywhere in the space.

Can I load my own floor plan?

Yes via GLTFLoader (SketchUp, Revit, ArchiCAD exports) or IFCLoader from web-ifc-three for native IFC. The WebXR and teleport code is geometry-agnostic. Add your floor mesh to the walkables array.

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 a window sill is too high. These cannot be reliably perceived from drawings or renders. They require being inside the space at human scale.

What Three.js version?

r169 via importmap from jsDelivr. No build step, no bundler, loads directly in any modern browser.

Written by Joshua Opolko, who builds browser-based XR and writes about self-hosting, AI, and immersive technology at joshuaopolko.com. Room dimensions follow typical high-ceiling residential loft proportions; furniture scale is realistic for the space. June 2026.