Build your own little world
SceneXP is open source under the MIT license, and new experiences are warmly welcomed through GitHub pull requests. A world to walk through, a game, a story, a simulation, or an experiment that exists to show what a browser can do. Whatever you have in mind, this page will get you building.
How the project is put together
There is no framework and no build step beyond minification. Each experience is a static folder of browser-native HTML, CSS, and JavaScript, powered by Three.js.
- One folder per experience. Every experience lives in its own folder
under
www/with its ownindex.html, config, and orchestrator. Styling comes from the shared versioned stylesheet inwww/shared/css, and an experience that needs rules of its own can add an optionalcss/experience.css. - A shared parts library.
www/shared/jsholds versioned, general-purpose modules (scene, lighting, controls, people, scenery, and more). An experience keeps its ownmain.jsorchestrator and assembles imported parts driven by one plain config object. - Three.js as a global. Each experience's
index.htmlloadslib/three.min.jsas a classic script before its module graph. - esbuild for minification.
npm run buildminifies JS and CSS. Every file underwww/is picked up automatically, so there is no build configuration to edit.
Pick an interaction model
Every experience so far follows one of four interaction models, and choosing one up front is the biggest design decision you will make. All four are assembled from the same shared parts, so the existing experiences double as working references. A new model is welcome too, if none of these fits what you have in mind.
- Explorable worlds. First-person scenes that visitors walk through, with keyboard and mouse on desktop, dual joysticks on phones, and collision so nobody wanders through a wall. Some also offer a guided autopilot tour.
- Composed views. A fixed camera frames one lovingly detailed subject, and the scene moves instead of the visitor. A row of floating buttons offers gentle pan and zoom, with matching swipe and pinch gestures on touch screens, and tapping props opens short lines of story. This is the simplest model to build and a great fit for small subjects. Fractal Garden extends it, keeping the fixed viewpoint but letting a tap on the ground plant a tree, so the visitor changes the scene rather than just looking around it.
- Hands-off rides. The scene drives itself and the visitor mostly watches, with play and pause, speed, and direction controls for light steering. The Mandelbrot dive is the reference: its auto zoom flies the camera while the visitor picks destinations and adjusts the ride. High Water is the strictest version, with no controls at all beyond starting and replaying.
- Piloted flight. The visitor drives a vehicle through open space rather than walking or watching, so the world moves around a camera that never stops. Earth Defense is the reference: keyboard and mouse on desktop, a throttle on the left thumb and a look joystick on the right on phones. Reach for this when the subject is the movement itself rather than the place.
Layer on the delight
Whichever model you choose, a few optional layers have proven to be the difference between a scene visitors look at and a scene they share:
- Discovery checklists. A short list of things to find in the scene, ticked off with a small celebration as visitors discover them.
- Tap-to-talk props. Objects and characters that respond to a click or tap with a short line of story. In a world built for someone, this is where their personality lives.
- Guided tours. An autopilot that drives the camera past the highlights until the visitor takes over.
- Featuring a business. An experience built for a business can carry its logo on the loading and welcome screens, a floating button to its website, and a warm invitation card that appears as visitors explore. Always with the owner's permission, and always in the spirit of a tribute rather than an advertisement.
The shared modules behind each of these live in www/shared/js, documented
part by part in its README.md.
Dress the shared controls
Every experience shares one welcome screen, loading screen, crosshair, joystick pair,
floating button set, and panel family. By default that chrome is a quiet near-white
that sits under any scene without competing with it. If your world has a mood of its
own, name a theme on your <html> element and the whole set follows
along:
<html lang="en" data-ui-theme="garden">
The themes live at the top of www/shared/css/styles-1.0.0.css, next to the
--ui-* tokens they set. Today's set is garden (leaf green),
surf (sea glass aqua), neon (stage-light rose), and
ember (deep-space amber). Leaving the attribute off keeps the default.
Adding a theme is six tokens copied from an existing block. Reach for a light tint of your hue rather than the brand color itself, since the welcome overlay is dark and most brand colors disappear against it. The test suite checks the contrast of every theme, so a mistake here shows up as a red test rather than an unreadable welcome screen.
One more token to know about. The mobile joysticks follow your accent unless you set
--ui-joystick-rgb, and they are a pair of filled circles sat low on the
screen, one on each side. In pink and flesh tones that arrangement reads as anatomy
rather than as controls, so a theme in that part of the spectrum points the joysticks
somewhere cooler and leaves the rest of its palette alone.
Run it locally
ES modules need to be served over HTTP, so run any static server from the
www folder:
cd www
python3 -m http.server 8000
# then open http://localhost:8000
Add your experience, step by step
- Fork the repository at github.com/stevendnoll/SceneXP and clone your fork.
- Create your folder, for example
www/your-world/. The existing experiences are the best reference: start from their structure with anindex.html, ajs/config.jsdescribing your world, and ajs/main.jsorchestrator that assembles parts fromwww/shared/js. - Follow the metadata pattern. Every experience page carries a strict same-origin Content Security Policy, full Open Graph and Twitter tags, JSON-LD, and a polite no-JavaScript fallback. Copy the pattern from an existing experience.
- Make a social card. A 1200 by 630 capture of your world, saved as
assets/og-<world>.webpwith a.jpgbeside it. Please read the conversion note in CONTRIBUTING.md before you make it, because a screenshot taken on a Mac carries the display's color profile and will come out visibly duller than what you were looking at unless you convert it properly. - Build and test. Run
npm run build(your new files are minified automatically), thennpm test. Please include a small unit test for your world, following thetestsfolder's<experience>-init.test.mjspattern. Every pull request should bring tests along for the code it adds or changes. - Add your world to the directory. The home page groups the
collection into three categories, so please pick the one your world belongs
to: Worlds and games for anything built for its own sake, Small business
tributes, or Personal tributes. Then add one card at the top of that group in
www/index.html, add your world at the top of the same category's structured-data list in that file's head, one URL inwww/sitemap.xml, and a short description under your category's heading inwww/llms.txt. The test suite checks that all four agree. - If your world remembers anything, say so in the privacy policy.
sessionStorageneeds nothing, since it goes when the tab closes and the policy already covers it. Anything you put inlocalStorageoutlives the visit, so it has to be named inwww/privacy.htmlalong with how a visitor clears it. The test suite keeps the list of files allowed to write persistent storage and will fail the moment yours joins them, which is the reminder rather than the rule. - Open a pull request telling us the story behind your world. The
mainbranch does not accept direct pushes, so every change to the project arrives this way, and we read every pull request with genuine delight.
House rules
- Give visitors something worth their time. That is the only test an experience has to pass here. Some of ours celebrate a real person, place, or business, and those are always welcome. So is a game, a simulation, or an experiment that honors nobody at all. Kind worlds only, please, whichever kind you bring.
- Security first. Same-origin CSP, no third-party scripts, no trackers, no CDNs. Everything ships from this domain.
- Accessible and considerate. Keyboard support, reduced-motion respect, and a no-JavaScript fallback are part of the pattern, not extras.
- Fast on phones. Many visitors arrive on mobile, so please keep assets lean and performance in mind.
- MIT licensed. Your contribution is published under the project's MIT
license. The bundled
three.min.jskeeps its own license.
Ready when you are
The source code is live at github.com/stevendnoll/SceneXP, and we would love to see what you build. If you have questions along the way, or a story you are excited to tell, please reach out and we will figure it out together.