An action, in this page's sense, is something an acting block does to the running world: write a value, start or stop an animator, send a message, make or remove a part, speak, play a sound. Actions are allowed only in acting blocks, that is, in the handlers of events and in on(created, ...). A value block (a derive, a declaration, a build) may not act (subscriptions.html).

The word is also used for what a being does (hail, ask, walk); those are triggers, on visitors.html. This page is about what the world's logic does in response.

The list

ActionWhat it does
set(path, value)Writes a base value once.
start(animator)Puts an animator into the tick; returns a handle.
stop(handle)Takes it out, leaving its value where it was.
send(message, to: part)Sends a message to a part, a being, a set of them, or the world.
spawn(d(...), under: parent, at: ...)Makes a copy of a design while the world runs; returns the new part.
remove(part)Removes a part and everything under it.
say(speaker, words, to: being, voice: frequency)Performs the act of speech, addressed to a being; voice:, optional, overrides the speaker's pitch for this line.
show(element, for: d)Shows a 2D layout element for a time (overlays.html).
play(sound, at: ...)Plays a sound once (proposed).
holdIntents(b, over: d, intents: [...])Holds a being's movement controls for a time; returns a handle (below).
throw(p, ...), sleep(p), wake(p)Sets a body moving; puts it to sleep; wakes it (proposed, below).
if c { ...; } else if d { ...; } else { ...; }Chooses among actions, inside an acting block in braces (events.html). A functional guard if(condition, action, ...) is not used.

play, throw and offer are outside the core list and are proposals.

set

set(path, value)
set(launched, now(sim))                         // the balloon
set(asked[v], true)                             // one row of a field keyed by being
set(hailing, start(together([...])))            // keep a handle in a field

Writes a base value once. The field must be declared mutable: true. A derived value is never set: to change a derived value, set one of its inputs, as the click sets launched and riding follows. Setting a value that an animator is writing is not settled; the animator would overwrite it at its next tick.

A timed step. The balloon cap's dip is a step down and, 0.25 s later, a step up. It is written as one animator of two keys jumped between:

start(keys(cap.offset, [key(sim(0 s), (0, -2 cm, 0)), key(sim(0.25 s), (0, 0, 0))], ease: steps(1)))

start and stop

let h = start(animator)
stop(h)

start puts a built animator into the tick and returns a handle by which it can be stopped or waited for (ended(h), marker(h, name)). Starting an animator on a value another animator is writing replaces the older one, from the current value. stop takes an animator out and leaves its value where it was: stopping Ariadne's thread when a being leaves the labyrinth leaves the line where it was laid (animators.html). A behavior from a package is started the same way: start(walkgait.walker(body)) (behaviors.html).

A handle may be kept in a local name (let reset = together([...]), then start(reset) and ended(reset)) or in a field (set(hailing, start(...)), then on(ended(hailing), set(hailing, None))).

send

send(message, to: target)
send(launch, to: target)                          // a path, here a field holding one (illustration)
send(launch, to: island.balloon)                // an absolute path
send(hailed(by: self), to: v)                     // a being
send(hailed(by: self), to: beingsWithin(self, 4 m))
send(paintLanded(at: p, by: c, struck: b), to: partsIn(court))     // everything in an area
send(stormComing, to: world)                      // the whole world

A message has a name and a typed value, like an action. The receiver's on(message(name, ...), ...) handles it and decides what it means; the sender need not know the receiver's type. The forms of address shown are proposed.

paintLanded is an example message carrying three things: where the paint landed, who threw it and the being it struck, if any. A creature told of paint in its court could wind up to charge.

A request to an engine might be written the same way, send(testContact(blade), to: physics) (an illustration); the general request to an engine is not settled. Throwing a body, and putting it to sleep or waking it, are actions of their own (below).

spawn and remove

spawn(d(field: value, ...), under: parent, at: place, ...)
remove(part)

on(became(health < 0.5), {                                  // illustration: a boss's army
  each i in 0 ..< 20 {
    spawn(troll(stance: oneOf([guard, charge, flank], seed: i)),
          under: army, at: ring(self, 6 m, i / 20));
  }
})

part splat                                                 // a paint splat
  field opacity: fraction = 1, mutable: true, lives: client
  field fading  : ?handle = None
  on(created, set(fading, start(transition(opacity, to: 0, over: sim(6 s), delay: sim(14 s)))))
  on(ended(fading), remove(self))

spawn makes a copy of a design while the world runs, as a child of under, and returns the new part. It is the same copy a load-time declaration makes; they differ only in when. The parent owns it: removing the boss removes its army. Its name is a numbered path under the parent; whether spawn numbers copies itself is open (designs.html).

exists(p) is true while the part p is in the world, and false once it has been removed; p may be a field holding None, which does not exist. A rule that waits for a spawned part to go reads it (the looking-glass's nearness rule, exists(echo)).

remove removes a part and everything under it. A lifetime is an animator plus a handler on its end, with no separate notion of lifetime: a splat is fully opaque for 14 s, fades over the next 6 s, and is removed when the fade ends. A lifetime on spawn itself (lasts: sim(3 s)) is proposed, but is not part of the notation.

say

say(speaker, words, to: being, voice: frequency)
say(g, answer(g, q), to: v)                      // the riddle
say(g, line, to: v, voice: 118 Hz)               // one line in a pitch of its own

Speech is an act; how it appears is the world's. A speaker (an NPC, a door, a radio, a player, a narrator) computes its words as a pure value, then performs the act at a moment. It puts the words nowhere. The world has a rule that answers every speech act, on(spoke(speaker, words, to: v), ...), and shows it (for a bubble, with show(element, for: d)) as its designer chose: a bubble above the speaker, a subtitle, speech from text, a chat-log line, several at once, or nothing out of earshot or through a wall. Only the act crosses the network; each visitor's machine shows it. Detail on visitors.html and overlays.html.

to: v names the addressee, not the audience. A line said by a guard is addressed to the asker, whose panel takes it as the answer to their question; but the act goes to every visitor's machine, so everyone near sees the plate over the guard's head and learns by watching that a guard refuses a second question. The asker's panel acts only for its own visitor. Nothing says who may see a line: that is the world's rule on spoke (overlays.html). voice: overrides the speaker's own pitch for one line (a speaker's voice field is its usual one). A line carries its words; the engine may compress lines on the wire, which content does not see.

play

play(sound, at: place, heardTo: distance, gain:, seed:, bus:, priority:, refDistance:, rolloff:)   // proposed
play(audiomixer.step(material: wood, weight: s), at: foot.heel, heardTo: 32 m)   // a footstep (illustration of the form)

A one-shot sound: a footstep, a knock, a cry. Besides at: and heardTo: it takes the sound options of Sounds. play is proposed; the alternative is to spawn a voice part that removes itself (spawn(audiomixer.voice(...), under: self, at: chest)). Whether a one-shot with no identity is a short-lived child or a plain action, or both chosen by whether anything addresses it or a late arrival must hear it, is open. audiomixer is a package; its recipes and placed voices are general.

throw, sleep and wake

throw(p, from: place, aim: place or ray, speed: m/s, reach: meters, missedAt: meters,
      ahead: meters = 0 m, flat: bool = false, rolling: bool = false, otherwise: direction)
sleep(p)
wake(p)

throw(ball, from: v.feet, aim: r, reach: 60 m, missedAt: 30 m, ahead: 1 m, flat: true,
      speed: 13 m/s, rolling: true, otherwise: bowlingPins.lane)       // the bowl

Each acts on a part that is a body (Physics: a body). throw takes the body from whatever had it (stopping an animator that was gliding it home), places it, and sets it moving toward its aim, awake; how the aim, the start and the motion are worked out is on Physics: throwing a body. sleep(p) stops the body where it is, with everything resting on or touching it, and wake(p) wakes it with everything asleep with it. The bowling green puts all its live props to sleep together once they have been nearly still for 0.8 s (Physics: acting on physics).

holdIntents

let h = holdIntents(b, over: duration, intents: [walk, turn, run, jump])

Holds a being's movement controls for a time: while it lasts, the server ignores the named intents of b, and gives them back when it ends. It blanks only the movement intents; the being's other actions, a cast among them, still work. It returns a handle, so ended(h) works on it. A newer hold on the same being replaces the older one. The zap holds its target for 1 s and the jig for 4 s (the island's server holds for the length and one step more, and the pose lasts exactly the length). This is world logic holding a being's controls; it does not make the being perform an action (Open questions).

offer

offer(ask, to: h)                                 // proposed

Makes a world's own action available to one being: after a hail, a guard offers the questions to someone it does not take for a killer. How the browser shows the offer (a panel, four buttons, a spoken menu) is the browser's (visitors.html).

What it means

How it connects

Open questions

← Events and triggers | Contents | Animators →