| name | basementuniverse-view-port |
| description | Use this skill when implementing or working with chunk-based viewport rendering systems in 2D games using @basementuniverse/view-port. Handles visible chunk computation, lazy chunk generation, chunk lifecycle management (update/draw), and FIFO cache eviction. Ideal for tile-based or grid-based world rendering where only visible + buffered chunks need processing.
|
Basement Universe View Port
Use this skill when working with @basementuniverse/view-port.
When to Use This Skill
Invoke this skill when:
- Implementing chunk-based rendering for 2D game worlds
- Setting up viewport/camera systems that need to manage visible chunks
- Optimizing large world rendering by only processing visible areas
- Creating procedurally generated worlds with lazy chunk generation
- Working with grid-based game systems that need efficient spatial queries
- Debugging chunk visibility, generation, or cache issues
Key Concepts
ViewPort is a lightweight chunk-visibility manager that:
- Computes visible grid cells from camera bounds
- Lazily generates missing chunks via a generator function
- Calls
update() and draw() on visible + border chunks
- Evicts old chunks using a bounded FIFO cache
Grid Coordinates: The library works in grid cells (not world coordinates). Each cell has:
- Grid position:
vec2(x, y) in cells
- World position:
vec2(x * gridSize.x, y * gridSize.y) in world units
Chunk Lifecycle:
- Camera moves → ViewPort computes visible grid range
- Missing chunks generated via
generator(gridPosition)
- All visible + border chunks get
update() called
- All visible + border chunks get
draw() called
- When cache exceeds limit, oldest chunks evicted (FIFO)
Installation
npm install @basementuniverse/view-port
Basic Usage Pattern
import { ViewPort, type ViewPortOptions } from '@basementuniverse/view-port';
class MyChunk {
private worldPosition: vec2;
constructor(gridCell: vec2, gridSize: vec2) {
this.worldPosition = vec2.mul(gridCell, gridSize);
}
update(dt: number, screen: vec2, camera: Camera) {
}
draw(context: CanvasRenderingContext2D, screen: vec2, camera: Camera) {
}
}
const viewPort = new ViewPort<MyChunk>({
gridSize: { x: 150, y: 150 },
generator: (cell) => new MyChunk(cell, { x: 150, y: 150 }),
border: 1,
});
function update(dt: number) {
camera.update(screen);
viewPort.update(dt, screen, camera);
}
function draw(ctx: CanvasRenderingContext2D) {
camera.setTransforms(ctx);
viewPort.draw(ctx, screen, camera);
}
Important Behavior Notes
-
Grid vs World Coordinates: The generator receives grid coordinates, not world coordinates. Convert to world space inside your chunk constructor if needed.
-
Generation Throttling: Maximum maxElementsToGenerate chunks are created per update() call to prevent frame drops when camera moves quickly.
-
Automatic Cache Sizing: The cache size (maxElements) may auto-grow to fit the current visible area plus buffer plus bufferAmount.
-
Chunk Persistence: Chunks are persistent objects until evicted from the cache. Store state directly in chunk instances.
-
Border Area: The border option loads chunks beyond the visible area. Increase this if chunks should be preloaded further out, or if chunks need to interact with neighbors.
-
Variadic Arguments: Both update() and draw() accept ...args which are forwarded to chunk methods. Use this to pass shared game systems/services.
Camera Requirements
The viewport requires a camera object with this shape:
interface Camera {
position: vec2;
readonly actualPosition: vec2;
scale: number;
readonly actualScale: number;
bounds: { top: number; bottom: number; left: number; right: number };
}
The bounds property is used for visibility calculations. See @basementuniverse/camera for a compatible camera implementation.
Debug Visualization
Enable debug overlays to visualize chunks:
const viewPort = new ViewPort({
debug: {
showOrigin: true,
showChunkBorders: true,
showChunkLabels: true,
}
});
Or enable all debug features at once:
const viewPort = new ViewPort({ debug: true });
Performance Tuning
Key options for performance optimization:
maxElementsToGenerate: Limit chunks created per frame (default: 10). Increase for faster generation, decrease if chunk creation is expensive.
bufferAmount: Extra cache headroom beyond visible area (default: 100). Increase if chunks are being evicted too aggressively.
border: Grid cells beyond visible area to load (default: 1). Increase for more preloading, decrease to reduce memory.
spatialHashMaxElements: Total cache capacity (default: 1000). Auto-grows if too small.
Common Patterns
Passing Shared Systems to Chunks
viewPort.update(dt, screen, camera, gameWorld, entityManager);
viewPort.draw(ctx, screen, camera, renderer, assetLoader);
class MyChunk {
update(dt: number, screen: vec2, camera: Camera, world: any, entities: any) {
}
}
Accessing Chunk Count
console.log(`Active chunks: ${viewPort.countChunks}`);
Getting Visible Chunks Directly
const visibleChunks = viewPort.getVisibleChunks(camera);
References