Scenes, layers & anchors
A scene
{
seed: "home", // any string or number; the same seed draws the same landscape
palette: "dusk", // a preset name, or your own colours
layers: 5, // a count, or a list of layers, back to front
height: "45%", // the band the landscape fills, from the bottom
haze: { strength: 0.5, curve: 1.2, color: "#f3b38a" },
}Every field is optional. With nothing set you get four rolling layers at dusk.
Lengths (heights, baselines, anchor positions) are px as a number, or a percentage as a string: "45%" is 45% of the element's height for vertical lengths, and of its width for horizontal ones.
Layers
Layers are listed back to front. Each one has a depth from 1 (the horizon) to 0 (the front), spread evenly by default, and depth sets the rest of its defaults: further layers sit higher, are smoother, have narrower hills, repeat over a longer width, fade more into the haze and lag more in parallax. So layers: 5 already looks like a landscape, and setting a field on one layer changes just that.
{
profile: "peaks", // "rolling" (default), "peaks", "mesa" or "dunes"
depth: 0.8, // 0 front, 1 horizon
baseline: "20%", // height of the lowest valleys, from the bottom
amplitude: "25%", // how far the highest crest rises above the baseline
roughness: 0.6, // 0 smooth to 1 craggy
wavelength: 500, // typical hill width, px
period: 2200, // the layer repeats every this many px
color: "#7a5a83", // instead of the palette and haze
mist: 0.4, // fade toward the haze colour in the valleys
seed: "back", // instead of one derived from the scene's seed
anchors: [ ... ],
trees: true, // a tree line: see below
lakes: [ ... ], // water: see below
}layers: [{ profile: "peaks" }, { profile: "mesa" }, { profile: "dunes" }, { profile: "rolling" }]Repeating: each layer is generated for one period and repeats without a seam, so any width works and nothing stretches: a wider screen shows more landscape. Periods differ between layers, so the repeats never line up.
Seeds: layer seeds are derived from the scene's seed and the layer's position in the list, so inserting a layer changes the ones after it. Give a layer its own seed to pin it.
Anchors
Put a peak, a dip or a flat stretch where you want it. The terrain around it blends in.
anchors: [
{ at: "70%", kind: "peak", height: "40%", width: 500 },
{ at: "25%", kind: "flat", width: "30%" }, // room for a heading
]| Field | Default | Meaning |
|---|---|---|
at | x position: px, or % of the element's width. | |
kind | "peak" | "peak" and "dip" lift or lower the terrain, keeping its detail; "flat" levels it over the middle half of its width. |
height | peak 115%, dip 0, flat 20% of the amplitude | Height above the layer's baseline at at. |
width | "20%" | How far its influence reaches, in total. |
layers: [
{ profile: "peaks", anchors: [{ at: "70%", height: "45%", width: 600 }] },
{ anchors: [{ at: "25%", kind: "flat", width: "35%" }] },
{},
]Anchors repeat with the layer's period, like the rest of it. In % they follow the element's width; in px they stay put.
Trees
A tree line along a layer's crest, part of the same silhouette:
trees: true
trees: {
kind: "conifer", // "deciduous", "mixed", one shape, a list, or weights: see below
height: 44, // px or %; default by depth, 44px at the front down to 12px at the horizon
density: 0.6, // sparse to a solid forest
cover: 1, // share of the ridge that's forest rather than clearing
variation: 0.3, // how much heights vary
color: "#24452c", // default: the layer's colour
seed: "woods",
}{ seed: 9, palette: "forest", layers: [{ profile: "peaks" }, { trees: true }, { trees: true }, { trees: { density: 0.85 } }] }Each tree picks a shape at random from the kind. "conifer" is mostly spruce and fir with some pine and cypress, "deciduous" is maple and oak with some poplar, and "mixed" is half of each. Or choose the shapes yourself:
| Shape | Silhouette |
|---|---|
spruce | A narrow triangle with jagged, branchy sides. |
fir | A smooth spire with gently curved sides. |
pine | Broad and round-shouldered, with flat-topped clumps along its top. |
cypress | A tall, narrow column with a rounded point. |
maple | A round crown with two lower shoulders. |
oak | Broad and lumpy: a cluster of round crowns. |
poplar | Tall and narrow, with a couple of bumps down its sides. |
kind: "oak" // only oaks
kind: ["spruce", "poplar"] // half and half
kind: { spruce: 3, fir: 1, oak: 1 } // weights: 60% spruce, 20% each of the otherslayers: [
{ profile: "peaks" },
{ trees: { kind: "mixed" } },
{ trees: { kind: { spruce: 2, pine: 1, oak: 1, poplar: 1 }, height: 56, density: 0.7 } },
]When shapes are mixed, broad crowns stand a little lower than spires, scaled so the average is still height; a single shape is exactly height tall. Trees repeat with their layer, stand on the ground at their feet, and skip cliffs. Layers are heights, so there's nothing to see under a crown: a dense row reads as a forest edge, while a lone maple or oak looks more like a bush. With color, the trees are drawn as a second shape behind the bare ground, so they can be darker or lighter than the hill they stand on.
Lakes
A stretch of water on a layer, reflecting everything behind it:
lakes: [{
at: "45%", // centre: px or % of the width
width: "30%", // px or % of the width; "100%" is water all the way across
level: "8%", // water height above the layer's baseline; default 12% of its amplitude
reflection: true, // mirror what's behind; false for flat colour
ripples: true, // streaks on the surface
color: "#7d97ab", // default: the sky's bottom colour, toward the land's
}]layers: [
{ profile: "peaks" },
{ profile: "peaks" },
{ trees: { density: 0.8 }, lakes: [{ at: "45%", width: "100%", level: "18%" }] },
]The ground under the water is held just below it, with a small bank at each shore and no trees. Everything drawn before the lake's layer (sky, sun, clouds, the ridges behind) is mirrored across the waterline and clipped to the water, then tinted more deeply further down. Layers in front of a lake hide it like they hide anything else, so a lake on the front layer (water down to the bottom edge) shows the most. Lakes repeat with their layer; one as wide as the element, or too wide to leave land between its repeats, carries on all the way across with no shores. With parallax, each reflection moves the opposite way to what it mirrors, as a real one would, so it stays true while you scroll.
Palettes and haze
A palette is a near colour (the front layer), a far colour (the furthest layer), a haze colour, a sky gradient and an optional default mist. Each layer's colour runs from near to far by depth, then fades toward the haze by strength × depthcurve. Mixing is done in OKLab, so fades stay even. Presets: dusk, dawn, alpine, forest, desert, fog, night, mono.
import { palettes } from "ridgescape";
palette: { ...palettes.dusk, near: "#1d1330" }
palette: { near: "#173a2b", far: "#5f8a6a", haze: "#dfe9d8", sky: ["#bfd8d2", "#eef3e4"] }Palette and haze colours are mixed ahead of time, so they must be hex, rgb(), hsl() or named. A layer's own color is used as is, so it can be anything CSS accepts, including var(--x).