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 own index.html, config, and orchestrator. Styling comes from the shared versioned stylesheet in www/shared/css, and an experience that needs rules of its own can add an optional css/experience.css.
  • A shared parts library. www/shared/js holds versioned, general-purpose modules (scene, lighting, controls, people, scenery, and more). An experience keeps its own main.js orchestrator and assembles imported parts driven by one plain config object.
  • Three.js as a global. Each experience's index.html loads lib/three.min.js as a classic script before its module graph.
  • esbuild for minification. npm run build minifies JS and CSS. Every file under www/ 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

  1. Fork the repository at github.com/stevendnoll/SceneXP and clone your fork.
  2. Create your folder, for example www/your-world/. The existing experiences are the best reference: start from their structure with an index.html, a js/config.js describing your world, and a js/main.js orchestrator that assembles parts from www/shared/js.
  3. 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.
  4. Make a social card. A 1200 by 630 capture of your world, saved as assets/og-<world>.webp with a .jpg beside 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.
  5. Build and test. Run npm run build (your new files are minified automatically), then npm test. Please include a small unit test for your world, following the tests folder's <experience>-init.test.mjs pattern. Every pull request should bring tests along for the code it adds or changes.
  6. 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 in www/sitemap.xml, and a short description under your category's heading in www/llms.txt. The test suite checks that all four agree.
  7. If your world remembers anything, say so in the privacy policy. sessionStorage needs nothing, since it goes when the tab closes and the policy already covers it. Anything you put in localStorage outlives the visit, so it has to be named in www/privacy.html along 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.
  8. Open a pull request telling us the story behind your world. The main branch 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.js keeps 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.