Render targets
Render into intermediate textures and reuse those outputs in scene composition.
Render targets
The canvas is the default render target — every context.backend.clear() and context.render(sprite) goes there. A RenderTexture is a second target: an off-screen surface you can draw into and then sample as a texture on a sprite, apply filters to, or composite back into the main scene.
This is the foundation of multi-pass rendering in ExoJS: render-to-texture for caching, minimaps, picture-in-picture views, reflection maps, and as a staging area before post-processing.
Creating a RenderTexture
A RenderTexture has pixel dimensions and optional sampler parameters:
import { RenderTexture } from '@codexo/exojs';
const rt = new RenderTexture(256, 256);
The constructor accepts an optional SamplerOptions object to control how the texture is sampled when used on a sprite:
import { RenderTexture, ScaleModes, WrapModes } from '@codexo/exojs';
const rt = new RenderTexture(512, 512, {
scaleMode: ScaleModes.Nearest, // default Linear
wrapMode: WrapModes.Repeat, // default ClampToEdge
});
Default sampler settings — linear filtering, clamp-to-edge wrapping, premultiplied alpha, no mipmap generation — match the typical “render-to-texture then display” use case.
Drawing into a RenderTexture
Set the render target on the backend, draw normally, then restore the canvas:
init(loader) {
const backend = this.app.backend;
this.offscreen = new RenderTexture(256, 256);
// Redirect rendering to the off-screen target
backend.setRenderTarget(this.offscreen);
backend.clear();
this.someSprite.render(backend);
this.someContainer.render(backend);
// Restore the canvas
backend.setRenderTarget(null);
}
Everything between setRenderTarget(rt) and setRenderTarget(null) draws into the RenderTexture instead of the canvas. The clear() call clears the render texture, not the canvas. After restoring the canvas, the RenderTexture holds the result as a sampled texture.
Using the result
Once drawn, a RenderTexture can be assigned to any Sprite:
this.display = new Sprite(this.offscreen);
this.display.setPosition(400, 300);
this.display.setAnchor(0.5);
this.addChild(this.display);
The sprite displays the off-screen render as its texture. You can position, scale, rotate, tint, and filter it like any other sprite.
Updating each frame
The render-to-texture step typically happens once during init for static content, or inside draw for content that changes per frame:
draw(context) {
// 1. Draw game world into the off-screen target
context.backend.setRenderTarget(this.offscreen);
context.backend.clear();
this.worldLayer.render(context.backend);
context.backend.setRenderTarget(null);
// 2. Draw the main scene — the off-screen result is now a texture
context.backend.clear();
context.render(this.display);
context.render(this.hud);
}
When a RenderTexture is used as the active render target, draw calls write into it directly. You do not need to call updateSource() after setRenderTarget(null).
RenderTexture as a RenderTarget
RenderTexture extends RenderTarget, which carries a View for camera control, size management, and viewport configuration. When drawing into a RenderTexture, the render target’s view determines the coordinate system. By default it uses a pixel-aligned view matching the texture dimensions:
import { RenderTexture, View } from '@codexo/exojs';
const rt = new RenderTexture(400, 300);
// Optionally set a custom view (camera)
const customView = new View(200, 150, 400, 300);
rt.setView(customView);
The setSize() method changes the texture dimensions. powerOfTwo reports whether both dimensions are powers of two — relevant for some mipmap and tiling scenarios.
Use cases
Cached layers. Render a complex, static container once into a RenderTexture, then display the result as a sprite. Subsequent frames skip the container’s render tree entirely — one texture draw instead of N child draws:
init(loader) {
this.buildComplexScene(); // builds this.staticLayer
this.cache = new RenderTexture(
Math.ceil(this.staticLayer.width),
Math.ceil(this.staticLayer.height),
);
const backend = this.app.backend;
backend.setRenderTarget(this.cache);
backend.clear();
this.staticLayer.render(backend);
backend.setRenderTarget(null);
this.cachedSprite = new Sprite(this.cache);
this.staticLayer.visible = false;
}
draw(context) {
context.backend.clear();
context.render(this.cachedSprite);
// ... dynamic content on top ...
}
Mini-maps. Render the full world from a zoomed-out view into a small RenderTexture, then display it scaled down in a corner sprite.
Compositing. Render two independent scene layers into separate RenderTexture instances, then composite them with different blend modes, tints, or filters applied to the result sprites.
Staging for post-processing. Render a scene into a RenderTexture, apply a filter to the sprite that displays it, and render the result to the canvas. The Post-processing chapter covers this pattern in detail.
RenderTexture vs. cacheAsBitmap
cacheAsBitmap on a RenderNode bakes the node’s subtree into an internal texture automatically. Use cacheAsBitmap when the cached content doesn’t need to be repositioned, scaled, filtered, or displayed in multiple places — it’s a simple on/off toggle. Use a RenderTexture when you need explicit control over when the cache updates, what view it uses, or how the result is displayed (multiple sprites, custom sampler settings, composited with blend modes).
Lifecycle
RenderTexture owns GPU resources. Call destroy() when the texture is no longer needed to release the backing framebuffer and texture. The engine does not garbage-collect GPU objects automatically.
Examples
A container of 25 sprites rendered once into a RenderTexture, then displayed as a single sprite alongside the original container for comparison.
A zoomed-out view of a tile map rendered into a small RenderTexture and displayed as a corner mini-map.
Where to go next
The next chapter, Pixel snapping, shows how to keep sprites, panels, and tilemaps crisp on the device-pixel grid without touching logical state. After that, the Effects section builds directly on render targets — in particular, Post-processing extends the render-to-texture pattern into multi-pass filtering and screen-space effects.