Renderer · interface

SurfaceTextureOptions

Explained in Hello world.

interface SurfaceTextureOptions
import type { SurfaceTextureOptions } from '@driftengine/core';

Properties

NameTypeDescription
effectsoptionalreadonly (SurfaceLayerEffect | undefined)[]What each layer does beyond its picture — rooms behind windows, windows lit by night, wear, animation, staying dry — one entry a layer, undefined for a layer with none. Read only where this texture is a material's albedo. See surfaceEffects.ts.
wrapoptional'repeat' | 'clamp'repeat tiles the image, clamp stretches its edge texels.
More

Repeat is the default because the case this exists for is a wall: one small image covering a large surface, with uvScale deciding how often it lands. Clamp is for an image that is a picture — a portrait, a sign — where a second copy of it appearing past the edge is a bug rather than a pattern.

colorSpaceoptional'linear' | 'srgb'How the image's values are encoded, so the shader can sample light rather than pixels.
More

linear is the default and the old behaviour: the bytes are handed to the shader as they are. That is right for a mask, a height field, anything whose numbers are the data.

srgb is right for anything that was authored to be looked at — a photo, a painted canvas, a biome tile. Those bytes are display values, and shading maths is linear, so multiplying a light into them without decoding first is a category error: mid-greys come out roughly twice as bright as they should, and the mistake is invisible until an output transform is applied and everything blows out at once. The GPU decodes SRGB8_ALPHA8 in the sampler, so this costs nothing per fetch and, unlike decoding in the shader, it happens before filtering — which is the only place it is correct.

filteroptional'linear' | 'nearest'How a texel is chosen when the image is magnified: smoothed between texels, or taken whole.
More

linear is the default and is every surface that shipped before this, which is right for anything photographic: a wall, a painted canvas, a biome tile, where the texel grid is an artefact of resolution rather than the subject.

nearest is for an image whose pixels are the subject — pixel art, an icon atlas, a hand-authored tile. Reported by a consumer whose block atlas is exactly that: linear magnification turns an authored tile into a smear as the camera approaches, and there was no way to ask for anything else. They composed their atlas with imageSmoothingEnabled = false and kept tiles at twice the resolution they wanted, and neither touches magnification — the smoothing happens in the sampler, after everything a caller controls.

Minification still blends between mip levels, and that is not the option being ignored. A tiled floor at a grazing angle minifies far past one texel per pixel, which is what mips exist for; taking the nearest level as well would trade a smear for a visible pop as the camera pulls back. So the choice applies where it was asked about, and within a level either way.

@driftengine/ui2d takes the same option and defaults it the other way, because a sprite sheet is usually pixel art and a world surface usually is not.

mipmapoptionalbooleanBuild a mip chain. On by default, and it is not a quality preference.
More

A tiled surface seen at a grazing angle — which is every floor and every corridor wall — minifies far past one texel per pixel, and without mips that undersampling is aliasing that crawls as the camera moves. It is the single most visible artefact a textured world can have. Off is for a texture drawn at roughly its own size, where the chain is memory spent on levels nothing will sample.

anisotropyoptionalnumberAnisotropic samples, when the extension is present. 1 disables it.
More

Mips fix the crawling and cost sharpness: a floor stretching to the horizon picks its mip from the worse of the two axes, so it blurs along the one that was still well sampled. Anisotropy is the standard repair, it is cheap at these sizes, and on a machine without the extension the clamp below silently leaves it at 1.