# rift_core
The mouth of an arcane rift on a flat ground plane: a jagged, breathing, lens-shaped tear with a
white-hot rim, a parallax churning abyss inside, and a halo of light on the ground. It uses a
premultiplied blend: the abyss covers the ground (alpha 1) and the halo only adds light (alpha 0).
The plane's UV is mapped to metres through `plane_size_x` and `plane_size_z`. The tear's outline is
a lens `half_length` long and `half_width` wide each side of its centre line, fullest in the middle
and pinched at the tips, with a jagged edge from `rift_noise` fBm that differs on each lip and
grinds slowly with time, and a slow breathing of its width. Inside, the abyss is three layers of
swirling, twisted noise seen at depths 0.25, 0.9 and 2.2 below the surface along the view ray, so it
reads as a shaft going down; the layers mix `deep_color` and `mid_color` and carry thin `hot_color`
filaments, with a darker core along the centre line. The rim is a flickering white-hot lip over a
`hot_color` sheath, and outside it a `mid_color` halo with licking tongues of light spreads over the
ground. The whole result fades out toward the plane's edges and is scaled by `gain`.
The `arcane_rift` graph (`rift/arcane_rift.procGraph`) draws its `mouth` output with it through
`coreMat` (premultiplied, culling off, depth writes off) on a 7 by 4 plane lifted 0.015 above the
ground, with `gain` wired to the graph's `intensity` input. In the Procgen Effects Showcase world, the `fx_rift` scene plays the graph.
The shader includes `rift_noise` with `#include "rift_noise"`.
## Properties
| Property | Type | Default | Meaning |
|---|---|---|---|
| `gain` | float | 1.0 | Multiplies the output colour (range 0 to 20). |
| `half_length` | float | 2.1 | Half-length of the tear along X, in metres of the plane. |
| `half_width` | float | 0.62 | Half-width of the tear at its fullest. |
| `plane_size_x` | float | 7.0 | Size of the plane along X, mapping UV to metres. |
| `plane_size_z` | float | 4.0 | Size of the plane along Z, mapping UV to metres. |
| `deep_color` | color | [0.02, 0.0, 0.08, 1] | Darkest colour of the abyss. |
| `mid_color` | color | [0.5, 0.09, 1.5, 1] | Swirl colour of the abyss, tint of the rim and colour of the ground halo. |
| `hot_color` | color | [1.2, 1.6, 4.0, 1] | Colour of the abyss filaments and the rim's sheath. |
# rift_streak
An additive energy streak for procgen particles: a velocity-aligned billboard card
(`zero_billboard_streak`, turned onto the element's `orient` and stretched by its `scale.y`) drawn
as a hot filament with a soft sheath. Lane 0 carries the HDR colour and opacity, lane 1.x a shimmer
phase. Along the card the streak tapers at both ends and is fuller toward the head; across it a
tight Gaussian core sits inside a wider sheath. The core bleeds toward white, and a shimmer at 37
radians per second plays over the whole streak. It returns the colour times its coverage times
`gain`, with the coverage as alpha.
The `arcane_rift` graph (`rift/arcane_rift.procGraph`) builds `streakMat` from it (additive, culling
off, depth writes off, `gain` wired to the graph's `intensity` input) and draws two outputs with it:
`sparks`, the bursts that arc out of the tear and bounce on the ground plus the smaller sparks they
throw, and `streaks`, the energy streaks spiralling up out of the rift. The graph turns each
particle onto its velocity, stretches it by speed, colours it from a violet and blue HDR ramp over
its life, and writes a random value into lane 1. In the Procgen Effects Showcase world, the `fx_rift` scene plays the graph.
The shader includes `@builtin::shaderModules.billboard`.
## Properties
| Property | Type | Default | Meaning |
|---|---|---|---|
| `gain` | float | 1.0 | Multiplies the output colour (range 0 to 50). |
| `vertexBoundsDilation` | float | 0.05 | How far the vertex hook moves a vertex past the mesh, in world units: the culling bounds grow by it so a moved vertex stays inside them. |
## Lanes
| Lane | Carries |
|---|---|
| `data0.rgb` | HDR colour. |
| `data0.a` | Opacity. |
| `data1.x` | Per-element shimmer phase, 0 to 1 of a turn. |
# rift_plume
A rising column of arcane light for the rift: an upright card turned about the world Y axis toward
the camera (`zero_billboard_axis`), filled with climbing, twisting wisps, brightest at the base and
fading into the dark. Lane 0 is the HDR colour and opacity, lane 1.x a per-card phase.
Across the card the column is a Gaussian body that narrows from full width at the base to 0.3 of it
at the top and sways on a sine that climbs with time. Two layers of `rn_fbm2p` noise, periodic along
y with a period of 16 and scrolled with `rn_wrap`, stream upward through it, so the loop is
seamless. The column fades in over the bottom 8 percent, falls off as `(1 - y)^2.2` toward the top,
and carries an extra glow right at the base. It returns the colour times its coverage times `gain`,
with the coverage as alpha.
The `arcane_rift` graph (`rift/arcane_rift.procGraph`) draws its `plume` output with it through
`plumeMat` (additive, culling off, depth writes off, `gain` wired to the graph's `intensity` input):
four cards spaced along X from -0.9 to 0.9 at height 3.6, each 2.2 to 3.4 wide and 7.5 tall,
coloured (1.1, 0.4, 3.0) at opacity 0.5, with a random phase each. In the Procgen Effects Showcase world, the `fx_rift` scene plays the
graph.
The shader includes `@builtin::shaderModules.billboard` and `rift_noise`.
## Properties
| Property | Type | Default | Meaning |
|---|---|---|---|
| `gain` | float | 1.0 | Multiplies the output colour (range 0 to 20). |
| `vertexBoundsDilation` | float | 1.7 | How far the vertex hook moves a vertex past the mesh, in world units: the culling bounds grow by it so a moved vertex stays inside them. |
## Lanes
| Lane | Carries |
|---|---|
| `data0.rgb` | HDR colour. |
| `data0.a` | Opacity. |
| `data1.x` | Per-card phase; the shader multiplies it by 10 and offsets the sway and the wisps with it. |
# rift_rock
Torn basalt rubble with glowing arcane seams: lit PBR stone whose seam emission follows lane 0.x
(heat), while lane 0.y varies the pattern per chunk. The fragment builds a `PbrSurface` and shades
it with `zero_pbr_shade` from `@builtin::shaderModules.pbr_shading`.
The pattern is 3D value noise over the mesh's own UV (scaled 6 by 3) plus the chunk's variation, so
it stays fixed on the chunk as it tumbles. One noise layer, folded about its middle and raised to
the 30th power, draws thin seams; a second varies the stone's brightness and roughness (0.73 to
0.88). The albedo is `base_color` darkened along the seams. The emission is `glow_color` times the
seam, the heat and a flicker at 9 radians per second, plus a faint constant seam glow and a dim glow
on downward-facing surfaces.
The `arcane_rift` graph (`rift/arcane_rift.procGraph`) draws its `rubble` output with it through
`rockMat`, on noise-displaced, subdivided octahedra that cast shadows. The `rift_rubble` compute
shader moves the chunks and writes their `data0` as (heat, seed, cycle phase, 0). In the Procgen Effects Showcase world, the `fx_rift`
scene plays the graph.
## Properties
| Property | Type | Default | Meaning |
|---|---|---|---|
| `base_color` | color | [0.09, 0.085, 0.095, 1] | Stone colour before noise and seams. |
| `glow_color` | color | [1.0, 0.3, 3.0, 1] | Colour of the seam and underside glow. |
## Lanes
| Lane | Carries |
|---|---|
| `data0.x` | Heat: brightness of the seam glow. |
| `data0.y` | Per-chunk variation: offsets the noise pattern and the flicker phase. |
·computeshader · born here
❒asset # rift_motes
One step of the arcane mote swarm, run as a `sim.shader` solver with a neighbour grid. Motes swirl
around the rift through a rolling vortex ring stirred by turbulence, and keep apart through
grid-based separation, so the swarm streams together with its motes kept apart. It runs one
invocation per mote in workgroups of 64.
For each mote the shader builds a desired velocity from four parts:
- a swirl around the vertical axis through the origin, `swirl * (0.45 + 1.4 * exp(-0.35 * rho))`,
fastest near the axis;
- a poloidal roll around the ring core at radius `coreR` and height `coreH`: up on the inside, out
over the top, down at the outer edge, at a rate set by `rollRate`;
- a smooth turbulence from summed sines of position and time;
- a pull back toward the ring core for any mote farther than `shell` from it, and a lift for any
mote below height 0.2.
It then visits every mote in the 27 grid cells around it and adds a push away from each neighbour
closer than `radius`, weighted by `(1 - distance / radius)^2`. The velocity eases toward the desired
one at a rate of `1 - exp(-1.6 * dt)`, takes the push times `separate * dt`, is capped at 4.5 units
per second, and moves the mote by `velocity * dt`.
## Bindings
| Binding | Access | What it holds |
|---|---|---|
| `P` | read_write | Positions, three floats per mote; the shader writes the new position. |
| `prev_P` | read | Positions at the start of the step, read for the mote itself and for its neighbours. |
| `v` | read_write | Velocities, three floats per mote; read and written back. |
| `gcfg` | read | Grid configuration, used by `zero_grid_cell` and `zero_grid_range`. |
| `grange` | read | Per-cell ranges into `gorder`, used by `zero_grid_range`. |
| `gorder` | read | Mote indices sorted by grid cell; the separation loop reads neighbours from it. |
The grid helpers come from `#include "@builtin::systems.procgen.grid"`.
## Parameters
| Parameter | Type | Default | Meaning |
|---|---|---|---|
| `count` | int | 0 | Number of motes. |
| `dt` | float | 0.0166667 | Step length in seconds. |
| `time` | float | 0.0 | Solver time in seconds; drives the turbulence. |
| `radius` | float | 0.35 | Separation radius. |
| `separate` | float | 7.0 | Strength of the separation push. |
| `coreR` | float | 2.8 | Radius of the vortex ring's core from the vertical axis. |
| `coreH` | float | 1.9 | Height of the vortex ring's core. |
| `shell` | float | 3.2 | Distance from the ring core beyond which motes are pulled back. |
| `swirl` | float | 1.7 | Speed of the swirl around the vertical axis. |
| `rollRate` | float | 0.45 | Rate of the poloidal roll. |
## Dispatch
The `arcane_rift` graph (`rift/arcane_rift.procGraph`) dispatches it from its `swarm` node, a
`sim.shader` over 900 points seeded in a cylinder of radius 4.2 and height 3.4, with a `v` (Vec3)
attribute, `neighborRadius` 0.75 and uniforms `radius` 0.75, `separate` 5, `coreR` 2.5, `coreH` 1.7,
`shell` 1.9, `swirl` 1.5 and `rollRate` 0.5. Each of those 900 leaders is drawn as a cluster of
eight motes by `rift_mote_cluster`. In the Procgen Effects Showcase world, the `fx_rift` scene plays the graph.
·computeshader · born here
❒asset # rift_rubble
Analytic, per-chunk periodic motion for rubble orbiting the arcane rift, run as a `sim.shader`
solver. Every chunk's state is a function of the solver time alone, periodic per chunk, so the loop
is seamless: a chunk grows in while still buried, shudders, rips free, spirals up into orbit,
climbs, then crumbles to nothing glowing hot, and is buried again for its next cycle at a new spot
around the rift. It runs one invocation per chunk in workgroups of 64.
Each chunk hashes its index into its own values: a period of 0.8 to 1.2 times `period`, a phase
offset, a starting angle, the radius where it tears loose (1.5 to 4.1), its orbit radius (2.1 to
4.0), the height it climbs to (1.4 to 4.6), a size, an orbit speed and a tumble axis. Through each
cycle its phase passes four stages: emerging (0 to 0.08), ripping free (0.08 to 0.26), climbing
(0.22 to 0.9) and crumbling (0.84 to 0.985). The orbit is stretched 1.2 times along X, larger chunks
orbit and spin more slowly, and the chunk bobs gently once free.
## Bindings
| Binding | Access | What it holds |
|---|---|---|
| `P` | read_write | Positions, three floats per chunk; written. |
| `orient` | read_write | Orientation quaternion per chunk (`vec4f`); written as a rotation about the chunk's axis. |
| `scale` | read_write | Scale, three floats per chunk; written. It grows in over the first 5 percent of the cycle and falls to zero as the chunk crumbles. |
| `data0` | read_write | Per-chunk lane (`vec4f`); written as (heat, seed, cycle phase, 0). |
Heat is `0.25 + 1.2 * rip * (1 - climb) * emerge + 2.5 * crumble`: the seams flare as the chunk rips
free and burn brightest as it crumbles.
## Parameters
| Parameter | Type | Default | Meaning |
|---|---|---|---|
| `count` | int | 0 | Number of chunks. |
| `time` | float | 0.0 | Solver time in seconds. |
| `period` | float | 16.0 | Base length of one cycle in seconds. |
| `spin` | float | 0.55 | Base tumble rate. |
## Dispatch
The `arcane_rift` graph (`rift/arcane_rift.procGraph`) dispatches it from its `orbiting` node, a
`sim.shader` over 72 points on a disc, with `orient` (Vec4), `scale` (Vec3) and `data0` (Vec4)
attributes and uniforms `period` 17 and `spin` 0.55. The graph draws each chunk as a
noise-displaced, subdivided octahedron with the `rift_rock` material, casting shadows; `rift_rock`
reads heat from `data0.x` and per-chunk variation from `data0.y`. In the Procgen Effects Showcase world, the `fx_rift` scene plays the
graph.
# rift_crack
An additive glowing ground crack for ribbons from `geometry.ribbon`: a thin white-hot seam inside a
coloured glow, with energy surges running outward from a centre (in world space) and fading with
distance (`reach`). On the ribbon `uv.x` runs along the crack and `uv.y` across it. The seam is a
tight Gaussian across the ribbon and the glow a wider one in `glow_color`. Two trains of surges
travel outward from `center` at different speeds, a slow noise flicker plays over them, and the
brightness falls off as `exp(-distance / reach)`. Fragments dimmer than 0.002 are discarded.
The `arcane_rift` graph (`rift/arcane_rift.procGraph`) draws its `cracks` output with it through
`crackMat` (additive, culling off, depth writes off). The cracks are ribbons 0.5 wide laid along
eleven trunk lines leaving the tear's rim, wandering on curl noise and forked by `curve.branch` into
three generations that narrow with each fork. The graph wires `gain` to its `intensity` input and
leaves the other properties at their defaults; the default `center` (-147.5, 0, 148) is the world
position of the `ArcaneRift` entity in the Procgen Effects Showcase world's `fx_rift` scene.
The shader includes `rift_noise` with `#include "rift_noise"`.
## Properties
| Property | Type | Default | Meaning |
|---|---|---|---|
| `gain` | float | 1.0 | Multiplies the output (range 0 to 20). |
| `center` | float3 | [-147.5, 0, 148] | World position the surges run out from and the falloff is measured from (only x and z are read). |
| `reach` | float | 3.5 | Distance scale of the falloff, `exp(-distance / reach)`. |
| `glow_color` | color | [1.0, 0.25, 3.2, 1] | Colour of the glow around the seam. |
# rift_mote_cluster
Draws a cluster of glowing motes per element. The mesh carries degenerate quads (all four corners at
one point, told apart by their UV) on a unit sphere; the vertex stage orbits each around its own
axis and expands it to a camera-facing sprite. The element's scale sets how far the cluster spreads,
so a simulated swarm of a thousand leaders draws as thousands of motes for the cost of a thousand
renderables. Lane 0 is the HDR colour and opacity; `size` is the sprite size in metres.
In `vertex_clip` each sub-mote takes a stable id from where it sits in the cluster mesh and hashes
it into three values. It circles a per-mote axis at 0.35 to 1.25 radians per second, at a radius
that breathes between 0.2 and 1.0 of its rest position, is placed through the element's origin, axes
and scale, and is expanded into a sprite `size` times 0.55 to 1.45 across. The three hashes pass to
the fragment as the vertex colour. The fragment draws a core and halo that twinkle at a per-mote
rate of 1.5 to 7.5 radians per second, leans each sub-mote's hue between a cool `(0.75, 0.85, 1.25)`
and a warm `(1.25, 0.8, 1.0)` tint of the cluster's colour, and whitens the core. It returns the
colour times its coverage times `gain`, with the coverage as alpha.
The `arcane_rift` graph (`rift/arcane_rift.procGraph`) draws its `motes` output with it through
`moteMat` (additive, culling off, depth writes off, `size` 0.055, `gain` wired to the graph's
`intensity` input). The 900 leaders come from the `rift_motes` solver; each draws a cluster mesh of
eight zero-size quads placed on a sphere shell, at a random spread of 0.6 to 1.0, coloured from a
blue-violet-pink ramp by a random hue. In the Procgen Effects Showcase world, the `fx_rift` scene plays the graph.
The shader includes `rift_noise` with `#include "rift_noise"`.
## Properties
| Property | Type | Default | Meaning |
|---|---|---|---|
| `gain` | float | 1.0 | Multiplies the output colour (range 0 to 50). |
| `size` | float | 0.06 | Sprite size of each sub-mote in metres, before its 0.55 to 1.45 variation (range 0 to 1). |
| `vertexBoundsDilation` | float | 2.1 | How far the vertex hook moves a vertex past the mesh, in world units: the culling bounds grow by it so a moved vertex stays inside them. |
## Lanes
| Lane | Carries |
|---|---|
| `data0.rgb` | HDR colour of the cluster. |
| `data0.a` | Opacity. |
# effectShowcase
The procedural effects of the Procgen Effects Showcase world. Each one is a `.procGraph` that plays
through a `Generator`, and every shader, material and module a graph draws with sits beside it in
this package, so the package carries everything its graphs need. Each graph's README says what it
makes, how to place it and what each of its inputs changes.
## Contents
| Folder | Graphs | What they make |
|---|---|---|
| `combat/` | `impact`, `muzzleFlash`, `tracer` | A round striking a hard surface, the bloom at a barrel as a weapon fires, and the glowing streak of a round in flight. They draw with `fxFlash`, `fxSmoke` and `fxSpark` in `combat/shaders/`. |
| `blast/` | `wall_blast` | A charge blowing a breach through a stone block wall, on a 9.6 s loop. |
| `storm/` | `storm`, `tower` | A thunderstorm around a lone tower: wind-driven rain, lightning striking on the schedule `schedule.module` keeps, and sparks and smoke where strikes land. `tower` is the stone keep it stands around. |
| `rift/` | `arcane_rift` | A rift tearing open in the ground, its motes and rubble moved by the compute shaders in `rift/compute/`. |
| `dragon/` | `dragon_breath` | A dragon's fire breath sweeping a courtyard: a flame jet, rolling smoke and drifting embers. |
| `launch/` | `launch` | A heavy-lift rocket liftoff on one looping timeline, with the heat-haze material `rk_haze_mat`. |
| `waterfall/` | `wf_env`, `wf_water`, `wf_spray`, `wf_foam`, `wf_mist` | A waterfall built in parts: the cliff, basin and boulders, the falling and still water, the droplets, the foam where the falls land, and the mist with its rainbow. Its water materials are in `waterfall/materials/`. |
| `shaders/` | | `fx_noise`, the noise functions the waterfall and wall blast shaders include. |
## Playing one
A graph plays on a `Generator` component bound to it:
```lua
-- `graph` is the graph's reference: the AssetRef `asset.resolve` or a search returns for it.
local e = entity.spawn("impact", { position = { 0, 1, 0 } })
e.component.add("Generator", { graph = graph, playOn = "load" })
```
Set a graph's inputs with the Generator's `params`, e.g. `params = { size = 3 }`.