ConeScript is the language a world for the 3-D web is written in. A world arrives as ConeScript, is checked, is built on the server and on each visitor's machine, and then runs. This page says what kind of thing a ConeScript text describes, how it differs from a program, what it leaves out on purpose, and how the rest of this manual is laid out and should be read.

A world, not a program

Every language embodies a paradigm: what it represents, and the surroundings it runs in. A general-purpose language such as Cone represents a program: one process acting on memory, whose code runs when something calls it. ConeScript represents a world: shared, alive, placed in space and in time, seen by many people at once through many cameras, on machines that trust neither each other nor the content.

So the differences are not confined to ConeScript's types. They run through the whole language. The ten differences:

DifferenceWhat it means in the languageWhere in this manual
Logic hunts for what happensNothing calls a lantern. Its logic says what it watches for (dusk; someone within 4 m; a condition becoming true, became(c); a condition holding for a time, held(c, for: d)) and decides, when that happens, whether to act. Values defined from other values follow their inputs as a spreadsheet's cells follow theirs.Subscriptions, Events
Time is in the languageAnimators move values over time; every duration names its clock; an animator may begin at a moment already past, so a machine that arrives late agrees with one that was there.Values: time, Animators
Space is in the languageEvery placed thing has a frame, of a few kinds, and an identity by its path in a tree: pathLanterns.lantern[12].glass.Parts, Frames
Distribution is in the languageA value lives on the client, the server or both; a server-only value is never sent; only acts cross the network, and each visitor's machine shows them its own way.Distribution
Many people at onceSome values exist once per visitor, with a lifetime; some once per camera (the rain round each eye, a speech bubble in each visitor's picture).Values: tables keyed by being, Distribution
GenerationMost of a world is made, not stored: from a recipe and a seed, so every machine makes the same rocks; some values are drawn afresh each run; descriptions become products at the resolution needed.Construction, Generators
DisciplineBlocks that define a value are pure and never act; every block runs within a budget, so one world's script cannot stall a shared server.Blocks, Bounded running
ArrivalContent arrives into a running world: a visitor joins late, an object is built while others walk about, approved packages from strangers join the vocabulary.Loading, Packages
Perception crosses dimensions2D and 3D are composed both ways, and the pointer is routed back through the composition.Images, Overlays
AuthoringFields carry units, ranges, defaults and descriptions for the tools people build worlds with.Values: units and ranges, Fields

The same contrast as a table, a program beside a world:

A program (Cone)A world (ConeScript)
What runs codea callsomething happening: a message, a change, a clock
Timeoutside the languagea value, with named clocks and animators
Where data ismemory, by addressa tree of placed parts, by path and frame
Machinesone processa server and many visitors, values placed on each
Usersone or nonemany at once, values per visitor and per camera
Datastoredmade from recipes and seeds, at the resolution needed
Trustthe program trusts itselfneither machines nor content trust each other: budgets, purity
Startingfrom nothinginto a world already running
Outputwhatever it writes2D and 3D composed, the pointer routed back

Principles

Four groups of principles shape the language. Each is stated with its reason, so that an author knows what the language will and will not do for them.

1. The goal: a world as downloadable files

The language captures content creation flexibly enough that a world can be described in files, downloaded and run. Any world is meant to be describable, not only one particular world.

2. Quality and speed, held in balance

The language aims at picture quality against latency, and so at worlds that are:

3. Content says what; the engine decides how

4. People work through tools; what is stored is their intent, at its smallest

What a world is made of

Six requirements:

  1. A tree of named parts. A part's path is its identity and its place of ownership, and paths are how parts refer to each other. A part is the language's one unit of organization, as a module is in Cone: a namespace with a path, holding child parts, fields, functions, triggers, materials, layouts, sounds and files (Parts).
  2. Designs and copies. Any part can be a design, and naming the design makes a copy that follows the design except where it says otherwise (Designs).
  3. Values and expressions, kept live: a value defined from others is recomputed when its inputs change, the clock among them (Values, Expressions, Subscriptions).
  4. Handlers: when something happens and a condition holds, change values or send requests to tools and engines (Events, Actions).
  5. Bounded procedures inside handlers and construction: conditions, loops, named values (Blocks, Control flow).
  6. A seed, and where a value lives (client, server or both), as properties of generation and state (Distribution).

Values change in exactly three ways: a subscription defines a value from others, derive(path, expression); an event does something once when something happens, on(trigger, action, ...); an animator is built as a value, then started, and moves a value over time in the tick beside physics: one of the library's kinds, or one the world writes as a step function (Animators: your own). Part 3 of this manual covers each.

What ConeScript leaves out, and why

Absent by design: memory management, concurrency, resource strategy, and building new tools. They follow from one principle:

Content states requirements; resources are the implementation's business. Content says how the world looks and behaves. How fast, how much memory, what latency, and how work is divided are decided below, by libraries and the engine.

Content may state priorities and qualities of experience ("this responds instantly when touched"), never mechanisms. Capability lives in the tools, not in the world's own logic: world authors compose the browser's tools; when they need more, the tool is extended and every world gains it.

So, compared with Cone, ConeScript has no permissions (uni, mut references), no regions or allocators, no borrowing or lifetimes, no raw pointers, no trust blocks, and no threads or actors. What remains of Cone is its fundamentals: local names, expressions, blocks whose last line, written without a semicolon, is their value, functions and closures, if, match, while and each, structs, enums, options, results, lists and tuples. Those are written as in Cone, and the pages of Part 1 say where ConeScript simplifies them.

Layers of logic

Logic in a world comes in layers, each able to do more than the one before. The layers are how the ceiling on world logic (below) is stated: a capability that needs more than the top layers a world's own designs may reach belongs in a package.

LayerWhat it can doExamples
Expressioncompute a value from other valuesa lantern's height from the ground; a glow share for the glass
Value over timea value as a function of the clockthe lamps' schedule; the balloon's ride; the rocking chair
Rulewhen something happens and a condition holds, do somethingcome near and the glass wakes; a button; a hard landing
Handler and state machinea design's response to messages, changing its state across several statesa lantern's dusk, dawn and touch; a monster's charge and stagger
Procedureconditions, loops and named valuesconstruction pipelines; a counted loop that places the lanterns
Library call by namehand a whole behavior to a packagea villager's walking and wandering; a flock of forty swallows; a gait

Relation to Cone

ConeScript's fundamentals are compatible with Cone's: a block, an if or an each written in ConeScript is a Cone block, if or each, minus anything about memory. The world constructs (parts, fields, derive, on, animators, durations that name their clock) have no counterpart in Cone and have their own spellings. Whether the finished notation stays Cone-like is still to be decided; this manual uses one provisional syntax throughout so the pages can be read together.

Cone itself is still the language of what lies below a world: the browser, its engines and its packages are written in Cone, and so would be any approved extension (Packages).

How to read this manual

The order of each page

Every reference page runs in the same order:

  1. What it is, in plain language.
  2. How you write it: the syntax, with small examples.
  3. What it means: when it runs, where it runs, what it may not do.
  4. How it connects to the rest of the language.
  5. Open questions: only the real ones.

Examples

A package named in an example is a real package. A line that carries // illustration shows a capability that no package provides yet, written as a vocabulary name.

The syntax, in brief

Minimal forms first

The language starts minimal: every capability is first a plain named function with parameters, and declarations take named options by the same argument rule. Shorthand (sugar) will be added later, only where use shows it helps: where a form is used often and a shorter form reads or writes more clearly.

A short example in both halves of the syntax, a world's lamp level and its lanterns:

field lampLevel: fraction = 0, within: 0 ..= 1, mutable: true   // the world's; every lamp reads it
on(dusk, start(transition(lampLevel, to: 1, over: world(15 min), begin: dusk.due)))
on(dawn, start(transition(lampLevel, to: 0, over: world(15 min), begin: dawn.due)))

part pathLantern                                         // a design: no frame of its own
  field near      : bool = false, lives: client                  // each visitor's own (derived: not mutable)
  field nearGain  : number = 1.45, within: 1 ..= 2       // fixed: a named number
  field gain      : number = 1, within: 1 ..= nearGain, mutable: true
  field gainTarget: number = 1, within: 1 ..= nearGain          // derived: not mutable
  part post: stake(), material: materials.lanternBlack
    area(self, sphere(radius: 4 m, at: (0, 0.2, 0)))
  derive(near, occupied(post, by: me))
  derive(gainTarget, {                                   // a value block in Cone form
    let lit = lampLevel > 0;
    if near && lit { nearGain } else { 1 }
  })
  on(created, start(chase(gain, toward: gainTarget, speed: rate(nearGain - 1, per: sim(0.4 s)))))

The first lines are world constructs; the braces hold an ordinary Cone block whose last line, written without a semicolon, is its value. (gainTarget is written out as its own value only to show a block; the if could equally sit inside the chase.)

The parts of this manual

Open questions

Contents | Next: Values and types →