Skip to content

Set up a Flatland scene

Create a Flatland instance, add objects, render each frame, and dispose it.

Create a Flatland, add objects to it, render each frame, and dispose it. The setup assumes an installed three-flatland project and a texture available at public/sprites/hero.png.

Flatland explains what the class owns and why. The Flatland API reference lists every constructor option, method, and uniform.

import { WebGPURenderer } from 'three/webgpu'
import { Flatland, Sprite2D, TextureLoader } from 'three-flatland'
const renderer = new WebGPURenderer()
await renderer.init()
document.body.appendChild(renderer.domElement)
function resizeRenderer() {
renderer.setSize(window.innerWidth, window.innerHeight)
}
resizeRenderer()
window.addEventListener('resize', resizeRenderer)
const flatland = new Flatland({ viewSize: 400, clearColor: 0x1a1a2e })
const texture = await new TextureLoader().loadAsync('/sprites/hero.png')
flatland.add(new Sprite2D({ texture }))
let animationFrame = 0
function animate() {
flatland.render(renderer)
animationFrame = requestAnimationFrame(animate)
}
animate()

flatland.add() dispatches on type, described in object routing.

import { Light2D } from 'three-flatland'
import { Mesh, PlaneGeometry } from 'three'
import { MeshBasicNodeMaterial } from 'three/webgpu'
// Sprite2D → batched via SpriteGroup
const sprite = new Sprite2D({ texture, anchor: [0.5, 0.5] })
flatland.add(sprite)
// Light2D → tracked by lighting system
const light = new Light2D({ type: 'point', position: [50, 50], color: 0xff6600 })
flatland.add(light)
// Other Three.js objects → added to internal scene
const geometry = new PlaneGeometry(10, 10)
const material = new MeshBasicNodeMaterial({ color: 0x6699ff })
const mesh = new Mesh(geometry, material)
flatland.add(mesh)

Call setLighting() with a preset. All sprites are lit by default; set lit: false on a sprite to opt out.

import { DefaultLightEffect } from '@three-flatland/presets'
const lighting = new DefaultLightEffect()
lighting.resolutionScale = 0.5 // Optional: half-resolution effect resources
flatland.setLighting(lighting)
const indicator = new Sprite2D({ texture, lit: false }) // always full brightness

Flatland disposes an attached effect’s GPU resources when you replace or clear it. See effect ownership for the full contract, and the lighting setup guide for presets, Light2D types, and custom effects.

For a canvas, resize the renderer when the canvas dimensions change, as in the Three.js setup. React Three Fiber resizes its Canvas renderer. Flatland synchronizes its managed camera and lighting resources during the next flatland.render(renderer) call.

To set a manual surface size, call flatland.resize(width, height). With canvas output, pass logical CSS pixels. With a render target attached, pass physical texture pixels. The destination attached when you call resize() determines the units for that manual sizing session, even if you change the destination later.

To resume automatic surface sizing and camera framing, set flatland.aspect = 'auto'. For a regular managed camera with a fixed ratio, assign a numeric aspect instead; this resumes automatic effect sizing while retaining that camera ratio. See the Flatland API reference for the complete sizing contract.

Every global has a matching TSL node: timeNode, globalTintNode, viewportSizeNode, pixelRatioNode, windNode, fogColorNode, and fogRangeNode.

import { Sprite2DMaterial } from 'three-flatland'
const material = new Sprite2DMaterial({
colorTransform: (ctx) => {
// Use the global tint node in a custom effect
const tinted = ctx.color.rgb.mul(flatland.globals.globalTintNode)
return tinted.toVec4(ctx.color.a)
},
})
const stats = flatland.spriteGroup.stats
console.log(`Sprites: ${stats.spriteCount}`)
console.log(`Batches: ${stats.batchCount}`)
console.log(`Visible: ${stats.visibleSprites}`)

Draw calls are not part of stats. Read renderer.info.render.calls after a frame instead.

Install @three-flatland/nodes to use posterize in this example.

import { Flatland, createPassEffect } from 'three-flatland'
import { posterize } from '@three-flatland/nodes'
const PosterizePass = createPassEffect({
name: 'posterize',
schema: { bands: 6 },
pass:
({ uniforms }) =>
(input, uv) =>
posterize(input, uniforms.bands),
})
const flatland = new Flatland({ viewSize: 400 })
const post = new PosterizePass()
flatland.addPass(post)
// Update a pass parameter
post.bands = 10

By default, passes run in insertion order, and each receives the previous pass’s output. An explicit order passed to addPass() changes that sequence. The pipeline initializes on the next render after a pass is added. See post-processing for the pipeline behavior, and the pass effects guide for creating custom effects.

import { RenderTarget } from 'three'
const target = new RenderTarget(512, 512)
const flatland = new Flatland({ renderTarget: target })
// Use the texture on a 3D mesh
mesh.material.map = flatland.texture
// Each frame: render 2D first, then 3D
flatland.render(renderer)
renderer.render(scene3D, camera3D)

Flatland defaults a render target with no color-space metadata to sRGB, which suits 2D color output. Set the target’s color space before its first GPU use, or pass a fresh target: changing that metadata after Three has allocated the target does not recreate its attachment format.

For linear or HDR output, declare the intent on the target. Flatland preserves explicit color-space and texture-type settings.

import { HalfFloatType, LinearSRGBColorSpace, RenderTarget } from 'three'
const hdrTarget = new RenderTarget(512, 512, {
type: HalfFloatType,
colorSpace: LinearSRGBColorSpace,
})
const hdrFlatland = new Flatland({ renderTarget: hdrTarget })
cancelAnimationFrame(animationFrame)
window.removeEventListener('resize', resizeRenderer)
flatland.dispose()
renderer.dispose()
renderer.domElement.remove()

This releases Flatland’s renderer state, sprite batches, render pipeline and pass effects. The cleanup above applies to the Three.js setup. Dispose application-owned textures and other assets when their owners no longer need them; Flatland does not replace their lifecycle management.