In development · WebGPU · three.js · React Three FiberIn development

threejs-props: The small things that make a street lived in.

threejs-props is in development, but usable today: decorateRoads() lines a road network with street lights, signs, mailboxes, power poles and fences, and Props draws them all as instanced meshes. Every prop is seeded, so each one looks different but rebuilds the same.

screenshot · props.html open ↗
A town junction lined with street lights, traffic lights, bins and hydrants, pylons in the distance
14prop kinds
32styles across them
4road surfaces
1mesh per shape and material
Getting started

Decorate a road in one call.

Hand decorateRoads() a road network (threejs-city's city.graph, or plain nodes and edges) and a world, and it returns plain JSON placements. Props turns them into instanced meshes. The API is still settling before the first release, so names may change.

three.jsthreejs-props
import { Props, RoadPath, decorateRoads, planPowerLine } from 'threejs-props'
import { World } from 'threejs-biomes'

const world = new World({ seed: 7 })
const placements = [
  ...decorateRoads(roads, world, { seed: 7, mailboxes: { style: 'eu' } }),
  ...planPowerLine([[-500, 300], [550, 420]], world, { spacing: 260 }),
]
const props = await Props.create({ scene, placements })

new RoadPath({ scene, height: world.height, points: [[0, 0], [80, 30], [200, 20]],
  width: 5, surface: { surface: 'gravel' } })

props.set({ night: 1, states: { wetness: 0.7 } }) // lamps on, everything wet
props.states.set(3, { damage: 1 })                 // prop 3 leans over
React Three Fiberthreejs-props/react
import { useMemo } from 'react'
import { Props, RoadPath, decorateRoads } from 'threejs-props/react'

function Street({ roads, world, night, rain }) {
  const placements = useMemo(() => decorateRoads(roads, world, { seed: 7 }), [roads, world])
  return (
    <>
      <Props placements={placements} night={night} states={{ wetness: rain }} />
      <RoadPath points={[[0, 0], [60, 20], [140, 10]]} height={world.height} width={4}
        surface={{ surface: 'dirt', states: { wetness: rain } }} />
    </>
  )
}
Install npm i threejs-props threejs-biomes three Full API reference → React components →
What's in the box

What is working now.

Every row without a "planned" tag is in the package and in the demo: a town junction, a gravel road with a power line, pylons across the fields and a gallery of every prop. Planned rows are on the roadmap.

01

Fourteen prop kinds

From mailboxes to transmission pylons.

Thirty-two styles in all: US and EU mailboxes, wood or concrete poles, cobra-head or post street lights, picket, rail, adobe and stone fences, five road signs and more. Each column in the gallery is a new seed: size, colour and detail change, and the same seed always rebuilds the same prop.

  • Mailbox (US)
  • Mailbox (EU)
  • Power pole
  • Transmission pylon
  • Street light
  • Fence
  • Road sign
  • Bench
  • Bin
  • Fire hydrant
  • Traffic light
  • Bus stop
  • Hay bale
  • Well
Rows of every prop kind and style, three seeds each
02

Streets that furnish themselves

Lights, hydrants, signals and signs.

decorateRoads() spaces street lights, hydrants, bins, benches and bus stops along urban sidewalks, puts traffic lights, stop signs and name signs at junctions, and keeps junctions clear. Props never stand in water, on the carriageway or on each other.

A decorated town junction with street lights and traffic lights
03

Country roads

Poles, mailboxes, fences and hay.

Rural roads get a power line down one side, mailboxes at lot frontages, fence runs and hay bales in the fields. Styles follow the biome: adobe walls and wells in dry country, stone in the mountains, rails in the taiga.

A gravel road with power poles, a rail fence and hay bales
04

Power lines that sag

Real catenary cables.

Poles and pylons that share a line id are strung together with cables that hang in a true catenary. planPowerLine() spaces pylons along a route between two places and slides them out of water.

A line of transmission pylons crossing open fields
05

Road surfaces

Asphalt, cobblestone, gravel and dirt.

A TSL road material with lane markings, worn tyre tracks, cracks and patches, cobblestones, gravel, and rutted dirt with potholes and a grassy crown. RoadPath drapes it on the terrain as a ribbon with curbs and sidewalks or sloped verges; threejs-city's roads can adopt it too.

Asphalt roads with markings and sidewalksasphalt
A gravel road and a dirt trackgravel and dirt
06

Lamps and signals

Street lights at night, traffic lights on a cycle.

Street lamps glow as night falls, driven by a number or a TSL node such as the sky's night value. Traffic lights cycle red, amber and green with a per-light phase, every trafficCycle seconds.

Street lights and traffic lights glowing at a junction at night
07

Weather and damage

Wet, snowy, burnt, leaning.

Each prop has its own threejs-weathering state, so storms and fires work on props directly. Wet props darken and shine, snow settles on top and weighs the cables down, burnt props char, and damaged poles, lights and signs lean over.

A rural road under snow: poles leaning after a storm, cables sagging under ice
08

Instanced from unit shapes

One mesh per shape and material.

Props are assembled from eight unit shapes and eleven shared materials. Every part of every prop is drawn through one InstancedMesh per shape and material, tinted per instance from typed arrays: the demo draws 230 props as 2,460 instances in 26 instanced meshes.

The props sandbox with its weather panel and a draw-call counterthree.js demo
09planned

Props across a generated world

Placed by threejs-worldgen.

Each prop already carries a placement rule (mailboxes near lots, pylons on links between settlements, street lights on urban sidewalks). Next: threejs-worldgen decorates every generated city and road with them and offers them in the asset gallery.

PLANNED

Furnish your streets.

threejs-props is in development: try every prop in the live demo, read the API reference, or follow along on GitHub until the first release.