MengTo/kage: An Interactive Five-Chapter Night Walk Through a Kyoto Mountain Temple, Rendered Live in Three.js
Introduction: Where Art Meets Code
Every web developer reaches a moment when they realize the browser can do far more than display forms and fetch APIs. It can render entire worlds—not static images or pre-recorded video, but living, breathing 3D environments that respond to your movements in real time. That's the territory Meng To explores with his open-source project, kage.
Meng To is no stranger to pushing boundaries. As the founder of Design+Code, he's taught thousands of designers and developers how to build polished, production-ready apps. His work has always straddled the line between aesthetics and engineering. With kage, he takes that philosophy to its extreme: a fully interactive night walk through a fictional Kyoto mountain temple, rendered entirely in the browser using Three.js.
At first glance, the project seems deceptively simple. You load a URL and find yourself at the base of a temple path. Lanterns glow, fog rolls through the trees, and as you move forward, the scene unfolds across five chapters. But beneath that serene surface lies a technical tour de force—custom shaders, instanced meshes, and performance engineering that keeps everything running at 60 frames per second.
For web developers, kage is more than a pretty demo. It's a masterclass in combining modern frontend tooling with WebGL. For artists, it's proof that the browser can serve as a legitimate medium for interactive storytelling. Let's dig into how it works.
The Vision: A Night Walk Through a Kyoto Mountain Temple
The Fictional Temple: Inspired by Kyoto's Architecture
The temple in kage doesn't exist. It's a composite of architectural elements Meng To observed across Kyoto—the sweeping curved roofs, the wooden pillars, the stone lanterns that line mountain paths. The design leans into the asymmetrical, nature-embracing aesthetic of Japanese temple architecture, where buildings feel like they've grown out of the landscape rather than been imposed upon it.
The choice of nighttime is deliberate. Darkness hides the edges of the 3D geometry, drawing the player's eye toward illuminated elements: lantern flames, the moon, the soft glow of temple windows. It's a trick borrowed from film—control what the viewer sees by controlling the light.
The Five Chapters: A Narrative Journey
The experience unfolds as a linear journey with five distinct acts:
- The Path — You begin at the base of a stone staircase, lanterns guiding your way upward through dense forest.
- The Gate — A traditional torii gate marks the transition from the mundane world to the sacred. The fog thickens here.
- The Courtyard — You emerge into an open space with a small garden, a pond reflecting the moon, and the main temple hall ahead.
- The Hall — You step inside the wooden structure. The perspective shifts from open air to intimate interior space, warmed by candlelight.
- The Summit — The final chapter takes you to a viewpoint behind the temple, overlooking a mist-filled valley. It's a moment of resolution.
Each chapter is a separate scene with its own lighting conditions and geometry. Transitions are triggered by player movement—crossing a threshold or reaching a certain point—rather than explicit prompts, keeping the experience fully immersive.
Atmospheric Design: Lanterns, Fog, and Nighttime Aesthetics
The atmosphere is the star of the show. The fog isn't just a background gradient; it's a dynamic shader that responds to the camera's position. Lanterns emit actual light that interacts with nearby surfaces. The moon casts a cool blue tint, while the lanterns provide warm orange accents. This color contrast—blue versus orange—is a classic visual storytelling technique that creates depth and mood without requiring complex textures.
Key Takeaway: The atmosphere isn't an afterthought. It's engineered through custom shaders and deliberate color grading. If you want your 3D scenes to feel cinematic, spend as much time on lighting and fog as you do on geometry.
Technical Foundations: The Three.js Stack
Why Three.js? The Power of WebGL in the Browser
Three.js is the most widely used JavaScript library for 3D graphics, with over 1.5 million developers using it worldwide. It wraps the low-level WebGL API—notoriously verbose and difficult to work with directly—into a clean, object-oriented interface. You create a Scene, add Mesh objects with Geometry and Material, position a Camera, and call renderer.render(scene, camera) in a loop.
For kage, Three.js provides several critical features out of the box: a built-in animation loop, a robust material system, support for GLTF models, and the ability to write custom shaders. It also handles cross-browser quirks, so the same code runs in Chrome, Firefox, and Safari.
React and Vite: The Modern Frontend Setup
The project uses React for state management and UI overlays, with Vite as the build tool. This might seem unusual for a 3D experience—why do you need React when you're just rendering a scene?
The answer is that React handles the "meta" layer: chapter progression logic, the loading screen, UI hints, and the integration between user input and the Three.js scene. The 3D rendering itself happens outside of React's component lifecycle, using a ref to access the WebGL canvas. This separation of concerns keeps the codebase organized.
Vite, meanwhile, provides instant hot module replacement during development and efficient bundling for production. It also simplifies handling assets like GLTF files and textures through its static asset management.
GLTF Models: Bringing the Temple to Life
The temple structures, lanterns, and environmental props are loaded as GLTF (GL Transmission Format) files. GLTF is the standard format for 3D content on the web—it's compact, supports PBR materials, and can include animations. The models in kage were created in external 3D modeling software (likely Blender) and exported as GLTF.
Using GLTF files rather than building geometry in code is a practical choice. It allows for high-fidelity models with intricate details—wood grain, roof curves, stone textures—that would be impractical to generate procedurally.
Key Takeaway: Modern 3D web projects don't require you to code every vertex. Use Three.js's
GLTFLoaderto bring in assets from tools like Blender, then focus your code on interaction, lighting, and performance.
Performance Engineering: Rendering 50,000+ Objects at 60 FPS
Instanced Meshes: One Draw Call, Thousands of Objects
Here's where kage gets technically interesting. The scene contains over 50,000 individual geometry elements—leaves on the trees, individual lanterns, stones on the path. If each were a separate mesh, the GPU would choke. Each mesh requires a draw call, and browsers can only handle a few thousand before frame rates collapse.
The solution is instanced meshes. Instead of creating 10,000 leaf meshes, you create one leaf geometry, one material, and then tell Three.js to render it 10,000 times with different positions, rotations, and scales—all in a single draw call. The GPU handles the repetition efficiently because the geometry data is reused.
In kage, this technique is applied to the leaves that fall through the air, the lanterns that line the path, and the scattered pebbles on the ground. The code defines an InstancedMesh with a count, sets the transformation matrix for each instance, and lets Three.js handle the rest.
Asset Optimization: Fast Loading and Compression
The live demo loads in under 5 seconds on a standard broadband connection—and that's not accidental. The GLTF models are compressed using Draco, a mesh compression library that dramatically reduces file sizes. Textures are resized and converted to WebP where supported. The entire scene is designed to fit within a reasonable bandwidth budget.
Profiling and Performance Benchmarks
The project runs at a consistent 60 FPS on mid-range hardware. This is achieved through a combination of techniques: limiting the number of shadow-casting lights, using low-poly geometry where possible, and culling objects outside the camera's view frustum. The code also uses a fixed timestep for the animation loop, ensuring that physics and shader animations don't behave differently on high-refresh-rate monitors.
Key Takeaway: Performance in 3D is about draw calls, not polygon count. Master instanced meshes and you can render scenes with millions of objects. Master asset compression and your users won't wait for a loading bar.
Custom Shaders: Crafting Atmosphere with GLSL
Understanding Shaders: The Basics
Shaders are small programs that run on the GPU, determining how every pixel of a 3D object appears on screen. There are two types: vertex shaders (which manipulate geometry) and fragment shaders (which determine color and lighting).
Three.js gives you access to these shaders through its ShaderMaterial class. You write GLSL (OpenGL Shading Language) code directly in your JavaScript, and Three.js compiles it for you. This is the most powerful way to customize the look of your scene.
Fog and Lighting: Creating Depth and Mood
The fog in kage isn't Three.js's built-in Fog class. It's a custom shader that interpolates between two colors based on distance—a deep blue near the camera, a lighter gray-blue at the horizon. The shader also applies a subtle noise pattern so the fog isn't uniform, giving it a more organic, swirling appearance.
Lighting in the scene uses a mix of Three.js's built-in lights (a directional light for the moon) and custom shader effects. The lanterns, for example, don't just emit a point light; they also use a shader on a transparent plane to create a glow effect that fades smoothly with distance.
Glow Effects: Making Lanterns Shine
The lantern glow is a classic sprite-based effect. Each lantern has a small plane facing the camera, textured with a radial gradient. The shader animates the gradient's intensity over time, creating a flickering effect that mimics a real flame. Because the glow planes are always facing the camera (a technique called billboarding), they look convincing from any angle.
Key Takeaway: Shaders aren't just for fancy effects—they're your tool for building atmosphere. If you want your scene to feel alive, learn GLSL basics. It's the difference between a screenshot and an experience.
User Experience: Navigating the Virtual Walk
First-Person Controls: Mouse and Touch
The controls are intentionally simple. On desktop, you click and drag to look around, and use the WASD or arrow keys to move. On mobile, you drag to look and use a virtual joystick or double-tap to move forward. The camera is constrained to a path—you can't walk off into the forest—which prevents users from getting lost or clipping through geometry.
Chapter Progression: Guiding the User
The experience uses invisible trigger zones to advance chapters. When the player crosses a certain point, the scene transitions via a crossfade—the current scene fades out, the next fades in—avoiding jarring jumps. The chapter title is briefly displayed on screen, reinforcing the narrative structure.
Accessibility and Mobile Support
The project includes several accessibility touches: adjustable mouse sensitivity, a "reduce motion" option that disables some particle effects, and compatibility with screen readers for UI text. Mobile support is solid, with touch controls that feel responsive on modern phones.
Key Takeaway: Good UX in 3D means constraining the user. Don't let them get lost. Guide them with light, path, and subtle triggers—not with arrows and pop-up instructions.
Educational Value: What Developers Can Learn
Creative Coding with Three.js
For developers who've only built standard web apps, kage is a gateway into creative coding. It shows that you don't need a game engine like Unity or Unreal to create immersive 3D experiences. A browser, a text editor, and Three.js are enough.
Integrating React with 3D Graphics
The project demonstrates a clean pattern for using React without fighting the imperative nature of Three.js. React components manage state and UI, while a separate module handles the Three.js scene. This separation is a valuable architectural lesson for any complex web project.
Open Source as a Learning Resource
Because the code is open source, you can read every line. You can see exactly how the instanced meshes are set up, how the shaders are written, how the GLTF models are loaded. This is a far better learning resource than a tutorial that shows isolated snippets.
Key Takeaway: The best way to learn advanced techniques is to read working code. Fork the repository, break it, fix it, and make it your own.
Community Impact and Reception
GitHub Stars and Community Engagement
The repository has amassed over 1,000 GitHub stars, a strong indicator of interest from the developer community. But the star count matters less than the nature of the engagement: developers are forking the repo, opening issues about performance, and sharing their own experiments based on kage.
Use Cases: From Portfolios to Virtual Tours
The project has found uses beyond its original scope. Developers have adapted the code for 3D portfolio sites, artists have referenced it for virtual tours of historical sites, and teachers have used the live demo in classrooms to explain real-time rendering and WebGL concepts. Game developers have taken the instanced mesh technique and applied it to render forests with thousands of trees at high performance.
Contributions and Forks
The open-source nature means anyone can contribute. There are forks that add new chapters, modify the shaders for different weather conditions, and port the experience to VR. The project serves as a foundation rather than a finished product.
Conclusion: The Future of Web-Based 3D Experiences
Summary of Key Takeaways
Kage is a proof of concept that the web is a serious platform for interactive 3D experiences. It demonstrates that with Three.js, modern build tools, and careful performance engineering, you can create cinematic, immersive environments that run in any browser.
The Growing Role of Real-Time Rendering on the Web
WebGL is no longer a niche technology. It's supported by every major browser, and the hardware to run it is in every modern laptop and phone. As WebGPU becomes more widely available, the gap between native and web-based 3D will continue to shrink. Projects like kage are early indicators of where the medium is heading.
How to Get Started with Your Own Three.js Project
If you're inspired to build your own 3D experience, start small. Load a single GLTF model into a Three.js scene. Add a camera and basic controls. Then iterate—add lighting, add fog, add a few instanced objects. The kage repository is an excellent reference to keep open while you work.
FAQ
What is MengTo/kage? It's an open-source GitHub repository created by Meng To, founder of Design+Code. It's an interactive, five-chapter night walk through a fictional Kyoto mountain temple, rendered live in the browser using Three.js.
Do I need a powerful computer to run it? No. The project is optimized to run at 60 FPS on mid-range hardware. It uses instanced meshes and compressed assets to keep performance high. A standard modern laptop or smartphone will handle it.
Can I modify the code for my own projects? Yes. The repository is open source. You can fork it, modify the shaders, add new chapters, or use its techniques as a reference for your own Three.js projects.
What are the five chapters? The Path, The Gate, The Courtyard, The Hall, and The Summit. Each represents a different stage of the journey up the mountain temple.
Is this a game? No. It's an interactive experience with no objectives, enemies, or scoring. It's closer to a virtual walk or an art installation than a game.
How do I navigate the walk? On desktop, use WASD or arrow keys to move and click-drag to look around. On mobile, use a virtual joystick and drag to look. The path is constrained, so you can't get lost.
What is the purpose of the project? It's an educational showcase for modern web-based 3D graphics. It demonstrates advanced Three.js techniques like custom shaders, instanced meshes, and GLTF model loading, all within a polished, narrative-driven experience.
Does it use any external 3D modeling software? Yes. The temple and environmental models were created in external 3D modeling software (likely Blender) and exported as GLTF files. The code then loads and renders these models using Three.js's GLTFLoader.
Ready to see it for yourself? Explore the live demo and dive into the source code on GitHub to see how you can create your own immersive 3D experiences with Three.js.