Minimap & previews
The WebGL minimap — terrain layers, marker overlays, fog-of-war, and camera frustum — and the embedded MeshPreview and CanvasView widgets for inventory icons and inspectors.
Meep ships two embedded-rendering widgets: a full-featured minimap that composites terrain, markers, and fog-of-war in a shared WebGL context, and a MeshPreview that spins up its own isolated WebGL context to render a 3D model inside an inventory slot or inspector panel.
MinimapView
MinimapView (in src/view/minimap/Minimap.js) is the top-level minimap container. It creates a MinimapWorldGL compositor, stacks layers onto it, and overlays DOM elements (camera frustum polygon) that track the live scene.
import MinimapView from "@woosh/meep-engine/src/view/minimap/Minimap.js";
const minimap = new MinimapView(entityManager.dataset, assetManager);
minimap.size.set(200, 200);
containerView.addChild(minimap);
The constructor connects to the ECS dataset directly; you do not pass terrain or cameras explicitly — they are discovered via EntityObserver when the view links.
MinimapWorldGL and layers
MinimapWorldGL (in src/view/minimap/gl/MinimapWorldGL.js) owns a Three.js Scene, an OrthographicCamera, and a WebGLRenderer pulled from the engine-wide WebGLRendererPool. It composites zero or more MinimapWorldLayer instances — each layer contributes a Three.js Object3D that the shared camera renders.
The camera is an orthographic top-down view. Its frustum is set by updateCameraFocus(), which reads worldBounds (a Rectangle) and projects the world-space footprint to the canvas. When canvasSize or worldBounds changes the renderer and all layers are notified automatically via SignalBinding.
The render loop runs via requestAnimationFrame. Each frame, update() calls layer.update(camera) for each layer and renders only if any layer raised needsRender.
MinimapView builds the following default layer stack:
| Layer class | Source | What it renders |
|---|---|---|
MinimapTerrainGL | src/view/minimap/gl/MinimapTerrainGL.js | Terrain preview texture on a flat PlaneBufferGeometry |
MinimapMarkersGL | src/view/minimap/gl/MinimapMarkersGL.js | Sprite-sheet markers for all entities carrying MinimapMarker + Transform |
MinimapFogOfWar | src/view/minimap/gl/MinimapFogOfWar.js | Fog-of-war mask sampled from the engine’s FogOfWar texture |
Custom layers can be added before MinimapView links:
this.worldGL.addLayer(myCustomLayer);
Terrain layer
MinimapTerrainGL reads terrain.preview.url to load a preview texture via AssetManager, then maps it onto a scaled plane. The plane’s world-space position and scale track terrain.preview.offset and terrain.preview.scale reactively. Mipmaps are generated for quality when zoomed out. A Cache<url, Texture> with maxWeight: 2 avoids redundant texture loads on terrain swap.
Marker layer
MinimapMarkersGL uses the particle subsystem (ParticleGroup) to store all markers as a THREE.Points object. Each entity with a MinimapMarker component is a particle with attributes for world position, display size, atlas UV patch, and sort z-index. A ManagedAtlas packs all marker icons into a single DataTexture; the custom GLSL material (buildMaterial) samples the atlas per-point. Markers are sorted by zIndex with an in-place quicksort before each render requiring reorder, so layering is respected without multiple draw calls.
MinimapMarker carries the icon asset URL, size, and z-index. Attach it alongside Transform to make an entity appear on the minimap:
import MinimapMarker from "@woosh/meep-engine/src/model/game/ecs/component/minimap/MinimapMarker.js";
entity.add(new MinimapMarker("textures/ui/icon-player.png", 16, 10));
Fog-of-war layer
MinimapFogOfWar renders a screen-space fog-of-war mask using a custom shader (buildScreenSpaceFogOfWarShader). It reads FogOfWar.texture (updated by the engine’s fog-of-war system) and computes a UV transform that maps the fog grid onto the visible area. When controlFocusArea is true the layer also drives the minimap’s worldBounds rectangle by computing the bounding box of revealed cells, keeping the minimap centred on explored territory.
Camera frustum overlay
MinimapCameraView (in src/view/minimap/dom/MinimapCameraView.js) is a DOM layer — an SVG <polygon> — that tracks every entity with a Camera + Transform pair. It casts the four screen-corner rays against the terrain (or falls back to the Y = 0 plane) and converts the intersection points to minimap-space, drawing a quadrilateral showing exactly what the in-game camera sees.
Link cycle: MinimapView.link()
→ EntityObserver fires cameraAdded for each Camera entity
→ MinimapCameraView constructed, added to __worldView
→ position/rotation signal bindings keep the polygon live
The minimap is also clickable: a PointerDevice on the world container fires focus(layerX, layerY), which maps screen coordinates back to world coordinates and sets the TopDownCameraController.target of the active camera.
MeshPreview
MeshPreview (in src/view/elements/MeshPreview.js) renders a single glTF/GLB model in its own isolated Three.js scene, suitable for inventory item icons and inspector panels.
import MeshPreview from "@woosh/meep-engine/src/view/elements/MeshPreview.js";
const preview = new MeshPreview({
url: "models/sword.glb",
assetManager,
animation: "Idle", // name of AnimationClip to auto-play, or null
allowRotationY: true, // drag-to-rotate Y axis
allowRotationX: false
});
preview.size.set(128, 128);
When the view links it acquires a WebGLRenderer from WebGLRendererPool, appends its domElement to this.el, and starts a requestAnimationFrame loop. Drag input is wired through a PointerDevice so the user can rotate the model by dragging. On unlink the renderer is released back to the pool and the animation loop stops, so the widget has zero GPU cost when not visible.
Supported file extensions are gltf, glb. An AnimationMixer plays the named clip if one exists in the asset; if the name is not found the model is static.
hooks
An optional hooks object provides two callbacks:
const preview = new MeshPreview({
url: "models/item.glb",
assetManager,
hooks: {
meshAdded(mesh) {
// mesh is the raw THREE.Object3D — apply tint, swap materials, etc.
},
sceneConstructed(scene, mesh, camera, group) {
// scene is the Three.js Scene — add extra lights or geometry
}
}
});
CanvasView
CanvasView (in src/view/elements/CanvasView.js) is a lightweight wrapper around HTMLCanvasElement that exposes a 2D context via this.context2d and keeps the canvas dimensions in sync with View.size.
import { CanvasView } from "@woosh/meep-engine/src/view/elements/CanvasView.js";
const canvas = new CanvasView();
canvas.size.set(256, 64);
// draw on link:
canvas.on.linked.add(() => {
const ctx = canvas.context2d;
ctx.fillStyle = "#3498db";
ctx.fillRect(0, 0, 256, 64);
});
CanvasView is used internally by SegmentedResourceBarView for its notch-mark overlay. It is the right choice for any HUD element that needs custom 2D drawing without the overhead of a full WebGL context.
Related
- UI toolkit —
View,GUIElement,GUIEngine, controls. - Widgets — radial menu, tooltips, currency, resource bars, drag-and-drop, modals, toasts.