So far the world has been one object on a floor. On this last page it becomes a place: a lawn under a real sky, where the sun crosses the sky as the day passes, six lanterns along a walk that light up together at dusk, and a doorframe standing alone on the lawn that takes you, when you walk through it, down into a cellar, a second place with no sky at all. The new ideas are a design and its copies, the sky and the time of day, and scenes joined by a portal.
The whole world
The lantern's shape and materials are as on page 4. What has changed is where everything lives.
part hello // the world
field dayLength: duration = sim(24 min) // new: a whole day passes in 24 minutes
field latitude: angle = 45 deg // new: where on Earth the sky is worked out for
field date: count = 288, within: 1 ..= 365 // new: the day of the year, 15 October
part materials
... // steel, amber and stone, as on page 4
part grass: plain(srgb(70, 105, 55)) // new
part garden: scene // new: the place you arrive in
field lampLevel: fraction = 0, within: 0 ..= 1, mutable: true // how lit every lantern is
part sky: skyDome(atmosphere: preetham(turbidity: 2.5), sun: sunFace),
at: around(camera, rotation: world)
part sun: sunLight(direction: sunDirection(latitude: latitude, day: date, hour: hour(now(world))),
color: sky.sunColor, lux: sky.sunLux, castsShadow: true)
part sunFace: sunDisc(direction: sun.direction)
part lawn: box(x: -10 ..= 10, y: -0.1 ..= 0, z: -15 ..= 5), material: materials.grass, at: (0, 0, 0)
solid(self, derived)
part gardenLantern // new: a design, not itself in the world
fn frame() shape { ... } // as on page 3
part body : frame(), material: materials.steel
part glass: box(x: -0.11 ..= 0.11, y: 0.94 ..= 1.2, z: -0.11 ..= 0.11), material: materials.amber
part lamp : pointLight(color: color(1, 0.6, 0.25), source: 2 cm, reach: 4 m, castsShadow: true),
at: (0, 1.07, 0)
derive(lamp.intensity, lampLevel * 60 candela)
part walk, at: (0, 0, 0) // new: six copies, three on each side
each k in 0 ..< 3 {
part left[k] : gardenLantern, at: (-1.2, 0, -2 * k)
part right[k]: gardenLantern, at: (1.2, 0, -2 * k)
}
derive(materials.amber.glow, lampLevel * 40 nits)
on(created, { // new: a world opened after dark is lit at once
let h = hour(now(world));
set(lampLevel, if h >= sky.duskHour || h < sky.dawnHour { 1 } else { 0 });
})
on(dusk, start(transition(lampLevel, to: 1, over: world(15 min), ease: linear,
from: current, begin: dusk.due)))
on(dawn, start(transition(lampLevel, to: 0, over: world(15 min), ease: linear,
from: current, begin: dawn.due)))
part door: join([box(x: -0.55 ..= -0.45, y: 0 ..= 2.1, z: -0.05 ..= 0.05), // new: a doorframe
box(x: 0.45 ..= 0.55, y: 0 ..= 2.1, z: -0.05 ..= 0.05), // standing alone
box(x: -0.55 ..= 0.55, y: 2 ..= 2.1, z: -0.05 ..= 0.05)]), // on the lawn
material: materials.steel, at: (3, 0, -2)
part way: portal(to: cellar.arrivals.foot, passage: true, window: false, // new: walk through it
mouth: box(x: -0.45 ..= 0.45, y: 0 ..= 2, z: -0.05 ..= 0.05))
part arrivals
part start, at: (0, 0, 3), facing: (0, 0, -1) // at the foot of the walk, looking up it
part cellar: scene // new: a second place, with no sky
part floor: box(x: -3 ..= 3, y: -0.1 ..= 0, z: -3 ..= 3), material: materials.stone, at: (0, 0, 0)
solid(self, derived)
part bulb: pointLight(color: color(1, 0.8, 0.6), reach: 6 m, castsShadow: true), at: (0, 2.2, 0)
derive(bulb.intensity, 40 candela)
part arrivals
part foot, at: (0, 0, 2), facing: (0, 0, -1)
One lantern, six times: a design and its copies
part gardenLantern has no at:, so it is not itself in the world. (Every part on these pages that is in the world says where with at:, or, like the sun, is placed by a direction; parts inside a placed part stand at its middle unless they say otherwise.) It is a design: a part that other parts copy. part left[k]: gardenLantern, at: ... makes a copy of it, placed. A copy has everything the design holds (the body, the glass, the lamp and its rule), and if you change the design, every copy follows.
The copies are made by a loop. each k in 0 ..< 3 runs its lines with k as 0, 1 and 2, and each time places a lantern on each side of the walk, 2 m further away. A part made in a loop is one of a numbered family: left[0], left[1] and left[2], so the far left lantern's glass is walk.left[2].glass.
The six copies share one mesh, hydrated once and drawn six times, so copies are cheap.
The nearness of pages 2 to 4 is gone: these lanterns follow the time of day instead, and every visitor sees them lit together.
A sky, and the time of day
Until now there was nothing behind the world. The sky part draws one: a dome of sky colored by the browser's model of the day sky, preetham (named for the clear-sky formula it starts from, carried on through twilight into night), with turbidity for how hazy the air is. It is placed around(camera, ...), so it stays round you however far you walk, and you can never reach it.
The world now has a clock of its own, and the root holds where and when the sky is: latitude and date, which the sky reads by those names. now(world) is the present moment on the world's clock, hour(...) gives its hour of the day, and dayLength says a whole day passes in 24 minutes of running time. The sun's direction is worked out from the hour, the day of the year and the latitude, so the sun rises, crosses the sky and sets, and the sky's colors follow it. The sun's color and brightness come from the sky, sky.sunColor and sky.sunLux, so it is orange and faint near the horizon and white at noon. sunFace is the sun's disc as you see it, a separate part from its light.
The sky also answers when dusk and dawn are: sky.duskHour and sky.dawnHour.
All the lamps at dusk
One field, lampLevel, now says how lit every lantern is, and each lantern's lamp, and the shared amber glow, follow it. Three rules move it:
duskhappens when the world's day passes the dusk hour. Atransition, an animator that moves a value to a goal over a set time, fades the lamps on evenly (ease: linear) over 15 minutes of the world's day, 15 seconds of running time.begin: dusk.duecounts from the moment dusk was due, so the lamps are where they should be even if the world was busy at that moment.dawnfades them off the same way.createdcovers the world being opened in the middle of the night: it looks at the hour and sets the lamps fully on or off at once.
lampLevel has no lives: client, so it is one value for the whole world, the same for everyone in it.
Scenes, and a portal between them
The world now holds two scenes, garden and cellar. A scene is a separate place with its own space: the cellar's floor at (0, 0, 0) is not under the garden's, or anywhere near it. Each scene has its own light; the cellar has no sky and no sun, only one bulb. What belongs to the whole world, like dayLength and the materials, sits on the world itself, above both scenes.
The only way between scenes is a portal. The door is a steel doorframe standing on the lawn, joined from three boxes, and way, inside it, is the portal: its mouth is the opening of the frame, and walking through it takes you to cellar.arrivals.foot. Because the portal names an arrival, you land where the arrival says and face the way it says (Portals: which way you face). window: false means you cannot see the cellar through the frame: you see the lawn behind it, until you step through.
Opening the world
Opening a world with scenes works as on page 1, one scene at a time. The browser builds the garden, the scene you arrive in, and starts it. It does not build the cellar until it might be needed: as you walk toward the door, it fetches and builds the cellar, so stepping through is immediate. You arrive at the garden's start, at the foot of the walk, looking up it.
Try changing it
- Set
dayLengthtosim(4 min)and watch a whole day and night pass quickly. - Change the loop to
0 ..< 10for a longer walk, and lengthen the lawn to match. - Bend the walk: add
0.4 * kto each lantern's x, and the rows drift right as they go. - Give the cellar a way back: a portal on its floor that names an arrival in the garden.
What you have now
Everything a small world needs. A design is made once and copied, by hand or in a loop. A sky and a sun follow the world's clock, and rules act at dusk and dawn. Scenes are separate places, joined by portals that land you at an arrival. Together with the first four pages (parts and recipes, materials, animators and rules, shaping from paths, and lights), that is the whole of the language in outline. The reference has the detail of each, for wherever you want to go next.
Still open
- Which arrival you get when you open a world with several scenes without naming one; here, presumably, the garden's
start. - What hour the world's day starts at when it first opens.