A program assumes one memory. A world runs on a server and on the machine of every visitor at once, and those machines must not all see everything: a puzzle's answer must stay on the server; a visitor's own view of the rain belongs to that visitor's camera. So distribution is in the language. This page says where values live, how secrets are kept, how values exist per visitor and per camera, what crosses the network, and how a shared server stays alive when strangers' content runs on it.
The author writes meaning, never machines. Most placement follows from what each piece of logic reads; the content states only what cannot be inferred, and never states network cost.
Where a value lives: client, server or both
How you write it. A field may say where it lives, in its lives: option after its default:
field liar : guard = draw([westGuard, eastGuard], per: run), lives: server // only on the server; never sent field asked : Table[being, bool] = false, mutable: true, lives: both // on the server and every visitor's machine field launched: moment = never, mutable: true, lives: server
| Home | Meaning | Example |
|---|---|---|
server | kept only on the server, which runs the world's logic; never sent to a visitor's machine | which guard lies |
both | kept on the server and on every visitor's machine, the same for all | whether a being has had its question, since every visitor can see a guard refuse a second one |
client | kept on each visitor's machine, its own | a value only one view needs |
A secret is simply a server field.
What it means. Where a field lives mostly follows from where the rules that read and write it run. If the server runs combat, the server's rules decide which fields change and what the protocol sends. The label is kept, partly to keep the protocol minimal, and is written only when it matters. A field says nothing about the network's cost; names follow meaning only.
Secrets
A server-only field is never sent. That is what keeps a per-run secret, such as the riddle's liar, out of a public description that anyone can download. A puzzle, a hidden treasure or a card game needs a value kept by the server, used by its rules, and shown to no one.
A secret also needs the right kind of randomness. A seed's draws are the same on every machine and every run, which is right for where the trees stand; a puzzle drawn from the seed would have the same answer every run, and anyone who read the content would know it. So the liar is drawn afresh each time the world starts running: draw(choices, per: run). A test must still be able to fix the draw.
Where logic runs
A block runs where its data is. Nothing in the riddle says where answer runs; it reads liar, which lives only on the server, so it runs on the server (Functions). A subscription whose inputs every machine has can be recomputed on every machine; one that reads a server field is computed on the server.
World rules run on the client and on the server. The server is not purely the browser's built-in executable: the content's rules run there too. The language provides addressable state, rule systems that run where the author says, and propagation of cause and effect; the engine detects changes, orders them deterministically, and ends cascades safely.
For now, the server runs animators and sends their results. Later, if wanted, the engine may infer which animators every browser can run from inputs it already has, and a linter may tell the author what costs updates. The cost depends on whether the inputs are on every machine, not on whether an animator is stateful.
Only acts cross the network
What it means. What crosses the network is what happened, not what it looks like: a guard said this line, to that being; the weather began changing to rain at this moment. Each visitor's machine manifests the act its own way. For speech, the world's rule on(spoke(speaker, text, to: v), ...) decides on each machine whether the words become a bubble, a subtitle, a voice or nothing out of earshot, and the visitor's preferences (captions, translation) may apply on top (Text: saying).
The cost of each of the three mechanisms for change:
| Mechanism | What crosses the network |
|---|---|
| Subscription | nothing, if every machine has the inputs |
| Event | the event, once |
| Animator | a pure animator: its parameters and start moment, once. A stateful one: stepped on every machine from the same inputs, or streamed |
Example, the weather. The server holds not the fifteen weather numbers but the change in progress (the blend it began from, the state it goes to, when it began and how long it takes), sends that when it changes and to a late joiner as they join, and every browser works out the numbers for any moment from the formula. Only the start of the change crosses the network. A guard's speech is the same: one act to every view.
Many visitors: values per visitor
Some values exist once for each visitor, with a lifetime: whether this being has had its question, kept while it is below ground. They are written as tables keyed by being, field asked: Table[being, bool] (Values: tables keyed by being), and like any field they live on the client, the server or both.
- Content never names a player. It names beings: bodies in the world that a person or the world drives. A being is an id the content may compare, use as a key and measure distance to.
- Outside the content are players, identity, avatars fetched for a person, authentication, payment and messaging; under the avatar proposal, also possession and the session, the registration of "this is my avatar", and the person's own settings: input mappings and their policy on what a world may do to their avatar. Where each belongs is on Outside the content.
- Lifetimes are stated by relation to the world: while the being is below, until it crosses the exit.
- Who holds which state is the author's policy: faction standing on the player, or a memory in each villager. How sophisticated the rules are, and who enforces them, are the author's choices too. The language provides the mechanisms; the author supplies the policy. Attributes are inputs to rules rather than intrinsic facts: a shirt shows green only under light that contains green.
- A visitor cannot act for another. The server turns a request's connection into the being that asked, so a browser cannot ask on another's behalf.
Many cameras: values per camera
Some things exist once per camera: the rain round each eye, a speech bubble in each visitor's picture. "The viewer" is the camera drawing the picture, not the player: looking through a far-seeing stone, the rain is round the projected eye and is that land's rain. So these parts exist per camera, and what they show is looked up where the camera is.
part rain: falling(kind: rain, radius: 9 m, above: 6 m, fall: 8 m/s), at: around(camera, rotation: world) // one per camera drawing derive(rain.strength, weather.rain) // the weather's rain, the same for every camera
A per-camera part is never sent and never stored on the server; each machine makes it for each camera it draws, from values it already has. Frame kinds, and which systems each registers with, are on Frames and Cameras.
Late arrival
A world is never "starting from nothing" for the person who walks in. What a late-arriving visitor sees follows from each value's declaration: a value that is a formula of a stored moment is worked out from that moment; an animator that began in the past is sampled at its time since start (Loading). Each client that joins is told what has been sent so far, from a replay log.
A joiner gets the state, never the one-shot acts. The state is the fields and the stored moments; the acts are the sounds and effects an event started once. A visitor who joins in the middle of a spell sees its pose from the right point, because the pose is a formula of a stored moment, and never hears the cry for a spell that began before they came. A message already delivered is not delivered again.
Products per machine
Each machine should build only the products it needs: the server the solids, each visitor's machine the meshes and textures (and solids for prediction). See Loading.
Bounded running on a shared server
One server runs the logic of a world for everyone in it, and content comes from strangers. So each block runs within a budget, and long work yields and resumes: a runaway loop in one world's logic must not stall the server (Control flow). Machines trust neither each other nor the content: a visitor's machine is not trusted with secrets, and content is not trusted with the server's time without limit.
How it connects
- Field declarations: Fields.
- Placement of logic: Functions, Blocks.
- Acts: Actions; speech: Text, Overlays.
- Beings and their actions: Visitors; what is not content: Outside the content.
- A visitor's machine holding one scene while the server may hold more: Worlds, scenes and regions.
- Per-camera parts: Frames, Cameras, Sky and weather.
- What a world may reach at all: Packages.
Open questions
- Where rules run: server, client, or the same rule on both, the server deciding and the client predicting, as movement does today. Separate sections of a world, or each rule labeled?
- Where an event's handler runs: closed. A rule inside a part with
lives: clientruns on each visitor's machine, and only there (Events). - A rule that a server field may be read only by logic that runs on the server, stated precisely.
- Per-view relevance: "drawn only for faces within 40 m of the being this browser drives" is neither client, server nor both.
- Things round each viewer's eye as parts with a camera frame, rather than outside the tree.
- Persistence: which server state survives a restart (the zone a visitor was in, their bags) and which resets (a lantern's glow). Bags belong to the visitor, who is outside the content.
- A sleeping region on the server: a region may keep running in full on the server while visitors' machines hold only its distant form; what that costs a shared server, and who decides (Worlds: a sleeping region).
- Multiplayer configuration (group size, raids, targeting): deferred.
← The vocabulary and packages | Contents | Outside the content →