Batch Rendering
SpriteGroup automatically batches sprites that share the same material into single draw calls. You don’t need to do anything special—just add sprites and the batching happens behind the scenes.
How It Works
When you add sprites to a SpriteGroup, they’re grouped by material and layer into efficient GPU batches. Systems run automatically during Three.js rendering — no manual update() call needed.
import { Sprite2D, SpriteGroup, Sprite2DMaterial } from 'three-flatland';
const spriteGroup = new SpriteGroup();scene.add(spriteGroup);
// These sprites share a material, so they batch togetherconst material = new Sprite2DMaterial({ map: spriteSheet });
for (let i = 0; i < 1000; i++) { const sprite = new Sprite2D({ material }); sprite.position.set(Math.random() * 100, Math.random() * 100, 0); spriteGroup.add(sprite);}
// In your render loop — no update() call neededfunction animate() { renderer.render(scene, camera); requestAnimationFrame(animate);}import { useMemo } from 'react';import { extend } from '@react-three/fiber/webgpu';import { Sprite2D, SpriteGroup, Sprite2DMaterial } from 'three-flatland/react';
extend({ Sprite2D, SpriteGroup, Sprite2DMaterial });
function Particles({ count = 1000, spriteSheet }) { // Create shared material const material = useMemo(() => new Sprite2DMaterial({ map: spriteSheet }), [spriteSheet]);
// Generate random positions once const positions = useMemo( () => Array.from({ length: count }, () => [Math.random() * 100, Math.random() * 100, 0]), [count] );
return ( <spriteGroup> {positions.map((pos, i) => ( <sprite2D key={i} material={material} position={pos} /> ))} </spriteGroup> );}Renderer Options
The SpriteGroup constructor accepts optional batch configuration:
const spriteGroup = new SpriteGroup({ maxBatchSize: 8192, // Max sprites per batch (default: 8192) autoSort: true, // Enable automatic sorting (default: true) frustumCulling: true, // Enable frustum culling (default: true) autoInvalidateTransforms: true, // Auto-sync transforms every frame (default: true)});scene.add(spriteGroup);Automatic Change Detection
Property changes on sprites are detected automatically through the ECS. When you update a sprite’s tint, alpha, flip, frame, layer, or position, the renderer syncs only the changed data to the GPU on the next frame. No manual invalidation needed.
// Just change properties — the renderer handles the restsprite.tint = [1, 0, 0];sprite.alpha = 0.5;sprite.layer = Layers.UI;sprite.position.x += 10;Performance Monitoring
Check batch efficiency with the stats property:
const stats = spriteGroup.stats;
console.log(`Sprites: ${stats.spriteCount}`);console.log(`Batches: ${stats.batchCount}`);console.log(`Draw calls: ${stats.drawCalls}`);console.log(`Visible: ${stats.visibleSprites}`);Goal: Keep batchCount low relative to spriteCount. If you have 1000 sprites but 100 batches, you’re not batching efficiently.
Optimization Tips
Share Materials
Sprites only batch together when they share the same material instance:
// Good: One material, one batchconst material = new Sprite2DMaterial({ map: atlas });sprites.forEach(s => s.material = material);
// Bad: Many materials, many batchessprites.forEach(s => { s.material = new Sprite2DMaterial({ map: atlas }); // Creates new batch each time!});Use Texture Atlases
Combine textures into a single atlas. All sprites using the atlas can share one material:
// Load a sprite sheet with frame dataconst { texture, frames } = await SpriteSheetLoader.load('/sprites/atlas.json');
const material = new Sprite2DMaterial({ map: texture });
// Different frames, same material = same batchconst player = new Sprite2D({ material, frame: frames.get('player') });const enemy = new Sprite2D({ material, frame: frames.get('enemy') });Organize by Layer
Sprites are sorted by layer before batching. Keep related sprites on the same layer:
import { Layers } from 'three-flatland';
// Background sprites batch togetherbackgrounds.forEach(s => s.layer = Layers.BACKGROUND);
// Entity sprites batch togetherentities.forEach(s => s.layer = Layers.ENTITIES);Next Steps
- Flatland Guide — Wrap SpriteGroup with camera, post-processing, and global uniforms
- Sprites Guide — Sprite2D properties and configuration