Documentation
    Preparing search index...

    Interface CanvasTextureOptions

    Construction options for a CanvasTexture.

    interface CanvasTextureOptions {
        anisotropy?: number;
        filter?: MaterialTextureFilter;
        maximumBytes?: number;
        minFilter?: MaterialTextureMinFilter;
        mipmaps?: boolean;
        wrap?: MaterialTextureWrap;
    }

    Hierarchy

    • Pick<TextureSource, "filter" | "wrap" | "mipmaps" | "minFilter" | "anisotropy">
      • CanvasTextureOptions
    Index
    anisotropy?: number

    How many anisotropic samples the backend may take when this texture is minified at a steep angle (§77's "anisotropy"; R-30b, 2026-08-21). An integer ≥ 1; defaults to 1, which is isotropic filtering and GL's own default.

    // A ground plane seen edge-on: mip levels alone blur it to mush.
    new Texture({ ...ground, mipmaps: true, anisotropy: 8 });

    Anisotropic filtering is an extension in WebGL 2 — EXT_texture_filter_anisotropic — so a conformant device may not have it, and every device that does has its own maximum. The policy here is §62's, not §85's: the backend clamps the request to the device's maximum, and where the extension is absent it uploads the texture with no anisotropy at all rather than failing. Presence is the capability, the stance this package takes for every optional renderer feature.

    The asymmetry with TextureSource.filter, which is refused when unknown, is deliberate and worth stating: "nearset" is a mistake in the scene, and no device will ever honour it; anisotropy: 16 is a correct request that some devices cannot fill, and a quality knob that turns a scene into an error on half the fleet is worse than one that quietly costs less. What §85 does refuse here is a value that is not an integer ≥ 1 — no device could honour that either.

    Anisotropy above 1 is only worth asking for together with mipmaps: true (it selects among mip levels per axis); the combination is not required and not refused, because a driver is free to do something useful with it and the texture is complete either way.

    How this texture is sampled between texel centres (§77; R-30, 2026-08-13). Defaults to "linear".

    // A 6 × 12 bitmap font: every glyph texel stays a square.
    const atlas = new Texture({ ...buildGlyphAtlas(), filter: "nearest" });

    The default is "linear" because that is what this tier sampled with before the field existed: a texture that names no filter issues the identical texParameteri pair it always did, so no already-authored scene moves a pixel (the rule R-15's colorSpace default follows, for the same reason).

    maximumBytes?: number

    §96 ceiling on width * height * 4 — refused at construction and on CanvasTexture.resize, and re-checked on every CanvasTexture.update against the size last recorded. Defaults to 64 MiB (a 4096 × 4096 RGBA8 surface); Number.POSITIVE_INFINITY is the explicit in-source opt-out. See the module header for the A-23 reasoning.

    How this texture is sampled when minified (§77; R-30b, 2026-08-21) — the mip-level-aware half of TextureSource.filter, which R-30 staged and this packet lands.

    // Crisp within a level, snapped between levels — pixel art at a distance.
    new Texture({ ...art, filter: "nearest", mipmaps: true,
    minFilter: "nearest-mipmap-nearest" });

    Defaults to the derived value, never to a constant:

    • with no mip chain, to TextureSource.filter — which is what this field's absence has always meant, and why a texture that names neither still issues the identical pair of texParameteri calls;
    • with mipmaps: true, to that filter's chain-aware form — "linear" → "linear-mipmap-linear" (trilinear), "nearest" → "nearest-mipmap-nearest". Building a chain and then not sampling it would be the one combination nobody asks for on purpose.

    A mip-choosing value without mipmaps: true is refused (§85): GL calls such a texture incomplete and samples it as opaque black, which is a whole-surface visual failure with nothing anywhere saying why. Refusing is this repository's rule for exactly that class of value.

    mipmaps?: boolean

    Whether the backend builds a full mip chain for this texture at upload (§77's "mipmaps"; R-30b, 2026-08-21). Defaults to false — one level, which is what every texture in the engine had before this field existed.

    // A ground texture the camera flies away from.
    new Texture({ width: 512, height: 512, data, mipmaps: true });

    It buys minification: a 512² texture covering twenty screen pixels takes twenty samples out of a quarter-million texels without a chain, and which twenty depends on the sub-pixel position of the camera — which is the crawling shimmer that appears the moment anything moves. With a chain the hardware samples a level whose texels are about the size of a pixel, and the image holds still.

    It costs a third more texture memory (Texture.byteLength counts the chain) and one generateMipmap at upload — both paid once per upload, and nothing at all on the draw path.

    WebGL 1 could neither mipmap nor REPEAT a non-power-of-two texture. WebGL 2 is GLES 3.0 and lifts both restrictions for ordinary uncompressed formats, so a 300 × 173 texture takes a chain here with no padding and no resize. (Compressed containers keep restrictions of their own — they are still deferred, see Texture.) A backend at §62's WebGL 1 tier is the one that would have to refuse the combination, exactly as it would have to refuse TextureSource.wrap's "repeat".

    A backend whose context cannot generate mipmaps at all uploads the texture with one level and an in-level min filter — degrading rather than leaving a texture GL would treat as incomplete (see @fourjs/render-webgl).

    How this texture is addressed outside [0, 1] (§77; R-30, 2026-08-13). Defaults to "clamp-to-edge", this tier's previous fixed choice.

    // A tiling ground texture, with uv running 0…8 across the plane.
    new Texture({ width, height, data, wrap: "repeat" });

    Note that "repeat" and "mirrored-repeat" are legal on a non-power-of-two texture in WebGL 2 (they were not in WebGL 1), so a backend at §62's WebGL 1 tier would have to refuse the combination rather than silently sample black.