ReadonlybackendWhich §62 backend this is.
Optional Readonlycompressed§62 "compressed textures": the compressed texture formats available, by
their canonical names ("bc7-rgba-unorm", "etc2-rgba8unorm", …), or an
empty list where none are.
Optional Readonlycompute§62 "compute shaders": whether the backend can dispatch compute (§82).
false on WebGL 2 is a true statement, not a shortfall — WebGL 2 has
no compute stage at all, and §62's tiers exist so that an application can
read that and pick the CPU path rather than discover it at dispatch time.
Optional Readonlyfloat§62 "floating-point targets": whether a render target may hold floating-point components rather than eight-bit normalised ones.
Optional Readonlyindirect§62 "indirect draw": whether draw arguments may be read from a buffer.
Optional Readonlymax§62 / §77 anisotropy ceiling: the largest TextureSource.anisotropy
this backend will honour, or 1 where anisotropic filtering is absent.
Optional with the same tri-state as the other WP-R1.1 members —
undefined means "not queried yet", which is the construction-time
answer on the GPU backends. Reading the WebGL extension at
initialize would move landed GL transcripts (R-30b's lazy-query
law), so @fourjs/render-webgl!WebglRenderer resolves this on
the first read of the field, after init, not during it.
Optional Readonlymax§62 "maximum bindings": how many resources one shader stage may bind at
once — texture units on WebGL 2, bindings per bind group on WebGPU. 0
for a backend that binds nothing.
Optional ReadonlymaximumThe most bones one skinned draw may use (§54, §62; RFC 0003), or 0
where skinning is unsupported.
Optional with the tri-state every WP-R1.1 member carries — undefined
means "this backend has not been taught to answer", distinct from 0 —
which is a recorded deviation from RFC 0003's required-member sketch: the
RFC predates the widening law WP-R1.1 landed (every added member is
optional, absent means not reported), and a required member here would
break every third-party Renderer for a number most backends answer with
a constant. The WebGL 2 backend reports @fourjs/render's declared
MAX_SKINNING_JOINTS (see mesh.ts for the portability arithmetic); a
skinned draw against it additionally requires its
registerSkinningPipeline() — the capability says what the backend can
do, registration is the application opting in to paying for it.
ReadonlymaxLargest texture edge length, in texels, the backend accepts
(§62 "maximum texture dimensions"). 0 means the backend has no textures
at all, which is the honest answer for NullRenderer.
Optional Readonlymax§62 "maximum uniforms": the largest uniform buffer binding, in bytes, a
single shader may see. 0 for a backend with no shaders.
Bytes rather than WebGL 2's "uniform vectors", because a byte size is the
quantity a caller sizing a buffer actually needs. The WebGPU backend
reports the device's maxUniformBufferBindingSize; the WebGL 2 backend
deliberately reports nothing here (R-30b — see webgl-renderer.ts for the
lazy-query law). Until 2026-08-29 this doc described a WebGL 2
MAX_VERTEX_UNIFORM_VECTORS-to-bytes conversion; no such code ever
existed.
Optional Readonlymultisampling§62 "multisampling": whether the backend can allocate a multisampled surface.
Optional Readonlyshader§62 "shader precision": the highest floating-point precision the fragment
stage supports, or "none" for a backend with no shaders at all.
"highp" on both WebGL 2 (GLSL ES 3.00 requires fragment-stage highp)
and WebGPU (WGSL's f32 is single precision by definition).
Optional Readonlystorage§62 "storage buffers": whether a shader may read and write a storage buffer.
Optional Readonlytexture§62 "texture formats": the render-target and texture formats this backend accepts, by their engine-side names.
Engine names, not backend names — "rgba8" means "eight-bit unsigned
normalised colour", and whether the backend spells that RGBA8,
rgba8unorm or bgra8unorm is its own business (§60a, render-target.ts).
A backend with no textures reports an empty list.
Optional Readonlytimestamp§62 "timestamp queries": whether the backend can time GPU work
(§84's GPU-side half). false on WebGL 2 without
EXT_disjoint_timer_query_webgl2, and false under SwiftShader.
What a backend can do (§62).
§62 requires capability reporting to cover maximum texture dimensions, texture formats, multisampling, floating-point targets, timestamp queries, storage buffers, compute shaders, indirect draw, compressed textures, shader precision, and maximum uniforms and bindings — and requires applications to be able to declare required and optional capabilities against that set.
Two members carried this record until WP-R1.1 (2026-08-21), when the WebGPU backend arrived and made the rest of §62's list answerable: a backend that can run compute has to be able to say so, and an application that needs compute has to be able to ask. The widening is deliberately done once, with all of §62's list, rather than a field per packet — a capability record that grows a member per pipeline churns every implementor once per pipeline.
Every added member is optional, and absent means "not reported"
The original wording of this doc is the reason, and it is kept because it is still the rule: reporting a field the backend has not queried would be worse than not reporting it, because capability negotiation is precisely the place where a confident wrong answer costs a crash. So the members below are optional rather than required, and
undefinedis a third answer distinct fromfalse— "this backend has not been taught to answer" rather than "this backend cannot". That also makes the widening additive in the strict sense (decision, WP-R1.1): every existing implementation, test double, and third-party backend still satisfies the type unchanged, which is the hazard §61 records about adding interface members.Coverage across the shipped backends is honest rather than total. NullRenderer answers every member with the floor;
WebglRendereranswers with WebGL 2's honest conservative values (computeShaders: falseis a true statement about WebGL 2, not a shortfall) but deliberately omitsmaxUniformBufferBytesandmaxBindings— R-30b's recorded law, a capability query must be lazy if the alternative moves recorded transcripts, applies verbatim to the two extragetParametercalls, and nothing in the engine reads either number yet (seewebgl-renderer.ts);WebgpuRendereranswers from the device's own limits and reportsmaximumSkinningJoints(RFC 0003's colour pair behindregisterSkinningPipeline()). This paragraph claimed the three backends "answer all of them" until 2026-08-29; the omissions above were deliberate from the day each backend's record landed.A consumer therefore reads a member as a tri-state:
§62's "applications may declare required and optional capabilities" is the other half, and it lives where the selection does (WP-R1.9):
RendererResolveOptions.capabilitiesinrenderer-registry.ts—"auto"skips a backend that does not affirm every required name, a named backend fails fast, and optional shortfalls are reported. The tri-state above is load-bearing there:undefinednever satisfies a requirement.Treat instances as immutable: a renderer publishes its capabilities once, at Renderer.initialize time, and callers only read them.