The block from page 1 just sits there. On this page it changes four ways: it becomes brushed steel, it turns slowly, it brightens when you walk up to it, and it hops when you click it. Each change brings in one new idea: a better material, an animator, an event, and a derived value that keeps itself up to date.
The whole world, changed
Lines marked // new are new or changed since page 1.
part hello // the world
part materials
part steel: physical(color: srgb(170, 172, 176), roughness: 0.35, metal: 1) // new
part stone: plain(srgb(140, 140, 135))
part floor: box(x: -5 ..= 5, y: -0.1 ..= 0, z: -5 ..= 5), material: materials.stone, at: (0, 0, 0)
solid(self, derived)
part block: box(x: -0.3 ..= 0.3, y: 0.4 ..= 1, z: -0.3 ..= 0.3), material: materials.steel,
at: (0, 0, 0)
field near: bool = false, lives: client // new: is this visitor close?
area(self, sphere(radius: 2 m, at: (0, 0.7, 0))) // new: the space round the block
derive(near, occupied(self, by: me)) // new
derive(tint, if near { 1.4 } else { 1 }) // new: brighter while you are near
part sun: sunLight(direction: (0.4, 1, 0.3), color: color(1, 0.96, 0.9), lux: 80000 lux,
castsShadow: true)
part arrivals
part start, at: (0, 0, 3), facing: (0, 0, -1)
on(created, start(keys(block.rotation, // new: one full turn every 12 seconds
[key(sim(0 s), rotation(0 deg)), key(sim(4 s), rotation(120 deg)),
key(sim(8 s), rotation(240 deg)), key(sim(12 s), rotation(360 deg))],
loop: loop, ease: linear)))
on(clicked(block), start(keys(block.offset, // new: a click makes it hop
[key(sim(0 s), (0, 0, 0)), key(sim(0.3 s), (0, 30 cm, 0)), key(sim(0.6 s), (0, 0, 0))])))
A material that looks like metal
Page 1's plain gave only a color. physical describes a surface the way modern renderers do, by how it reflects light. Its roughness runs from 0, a mirror finish, to 1, completely matte; 0.35 gives the soft sheen of brushed steel. metal: 1 says the surface is metal, so its reflections take on its own color, as steel's and brass's do, where paint and plastic reflect white.
A material can also carry a pattern. A wooden block is the same box painted by a pattern of boards:
part oak: [physical(color: white, roughness: 1), paintedBy(surfacepatterns.PlankParams.decking(512, seed: 3))]
The list says: start from a plain matte surface, then paint it with the planks pattern. The pattern is made by the browser from a seed, like the shapes, so no image is downloaded. Textures and surface patterns has the other patterns: shingles, flagstones, stone, bark and brick.
Turning: an animator
An animator changes a value over time. keys is the simplest kind: it takes the value through a list of keyframes, each a time and a value, and moves smoothly between them. Here the value is block.rotation, how the block is turned, and the keys take it a third of the way round every 4 seconds. loop: loop starts again from the first key when the last is reached; since 360 degrees is the same as 0, the turn never stops or jumps. ease: linear keeps the speed even.
Times are written with their clock. sim(4 s) is 4 seconds of the world's running time, which every visitor's browser and the server count alike, so everyone sees the block at the same angle.
The block on page 1 had rotation: rotation(30 deg) on its line. It is gone: the animator now owns the block's rotation, and a value is set by one thing at a time.
Starting it: events
An animator does nothing until it is started. on(trigger, action) is an event rule: it runs its action each time the trigger happens. created happens once, when the world has been built and starts running, so the turning begins as soon as you arrive. start(...) is the action that sets an animator going.
The second rule's trigger is clicked(block): someone clicked the block. Its action starts another keys, on block.offset, how far the block stands from where its line put it. The keys lift it 30 cm and set it back down in just over half a second. Because the offset only moves it, the block keeps turning while it hops.
Responding to you
The block brightens while you are within 2 m of it. Four lines do this, and each is a new idea:
field near: bool = falsegives the block a value of its own, true or false. A part can hold as many fields as it needs.lives: clientsays the value is kept on each visitor's own machine: if two people visit, each has their ownnear.area(self, sphere(...))marks out a space round the block, a ball reaching 2 m out from its middle. An area is invisible; the engines watch who is inside it.derive(near, occupied(self, by: me))keepsnearequal to whether you, the visitor on this machine, are inside the area. Aderiveworks like a spreadsheet cell: whenever what it reads changes, the value is worked out again.derive(tint, ...)keeps the block's tint at 1.4 while you are near and 1 otherwise. A part's tint multiplies the color it is drawn in, so 1.4 is 40% brighter.
Because near lives on each visitor's machine, the block brightens for whoever is standing beside it, on their own screen. Nothing is sent over the network.
What runs when
The world still opens as on page 1: the browser builds every part, then starts the world. Now there is something to run. On every tick of the world's clock, the turning animator moves the block a little further; the engines check who is inside the area; and any derive whose inputs changed is worked out again. A click is noticed when it happens, and its rule runs then.
Try changing it
- Make it turn faster by shortening the key times, or the other way by counting the angles down.
- Swap the steel for the oak above, and change
material: materials.steeltomaterials.oak. - Make the hop higher, or add a key so it bounces twice.
- Widen the area to 4 m, so the block notices you from further away.
What you have now
Four more ideas. A physical material describes a surface by how it reflects light. An animator changes a value over time, timed on a clock. An event runs an action when its trigger happens. A derive keeps a value up to date with what it reads. The next page leaves the turning and hopping behind and grows the block into a lantern.
← Guide 1: A first world | Contents | Guide 3: Grow it into a lantern →