(canvas …)
Configures how the canvas composites with the page. An optional singleton:
declare it at most once, with no :name.
Syntax
Section titled “Syntax”(canvas :alpha-mode opaque)| Key | Type | Required | Default | Description |
|---|---|---|---|---|
:alpha-mode |
symbol | No | opaque |
opaque or premultiplied |
:alpha-mode
Section titled “:alpha-mode”| Value | Behaviour |
|---|---|
opaque |
The alpha channel is ignored and the canvas composites as opaque. Cheaper, and it avoids fringing on a coloured page background. This is the WebGPU spec default. |
premultiplied |
Colour values are premultiplied by alpha and blended with the page, so a shader can render genuinely transparent regions. |
With the form absent the canvas is opaque, exactly as
GPUCanvasConfiguration.alphaMode specifies. Only the deviation costs anything:
write the form when you want the page to show through.
Examples
Section titled “Examples”Opaque canvas
Section titled “Opaque canvas”opaque is the cheaper composite and removes any chance of edge fringing on a
coloured page. It is also what a document with no (canvas …) gets, so saying
nothing and saying opaque compile to the same bytes:
(canvas :alpha-mode opaque)Transparent overlay
Section titled “Transparent overlay”premultiplied blends the canvas with the page, so a clear value with alpha 0
and a fragment that writes alpha below 1 both let the page through:
(canvas :alpha-mode premultiplied)
(shader-module :name code :code """ @vertex fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f { return vec4f(f32(i) - 1.0, f32(i & 1u) * 2.0 - 1.0, 0.0, 1.0); }
@fragment fn fs() -> @location(0) vec4f { return vec4f(0.9, 0.2, 0.1, 0.5); // half transparent }""")
(render-pipeline :name pipe :layout auto (vertex :module code :entry vs) (fragment :module code :entry fs (target :format preferred-canvas-format)))
(render-pass :name draw (color-attachment :view context-current-texture :clear-value [0 0 0 0] :load-op clear :store-op store) :pipeline pipe (draw :vertex-count 3))
(frame :name main :perform [draw])examples/pngine_background.sjon in the engine repository is the worked case.
How it travels
Section titled “How it travels”The value rides a header flag of PNGB (PNGine’s compact bytecode) rather than
the opcode stream, and the flag is clear for opaque. The JS runtime consumes
it at context.configure(), before the executor (the small WASM interpreter
that plays the bytecode) runs. The --flat export, a pre-decoded command stream
for the small main-thread player pngine/mini, mirrors it in its own flags
byte, and --html emits a second configure() only when the flag is set.
Native --frame rendering is offscreen and has no page to composite with, so it
ignores the form entirely; a (canvas …) never changes a CLI-rendered PNG.
Validation Rules
Section titled “Validation Rules”| Rule | Error |
|---|---|
Declare at most one (canvas …) per document |
duplicate (canvas …) form, declare canvas configuration at most once |
:alpha-mode must be opaque or premultiplied |
not_member |
(canvas …) takes no :name |
unknown_key |
WebGPU Mapping
Section titled “WebGPU Mapping”context.configure({ device, format: navigator.gpu.getPreferredCanvasFormat(), alphaMode: 'premultiplied', // from :alpha-mode; 'opaque' when the form is absent});Related
Section titled “Related”(limits …)- The other device-configuration singleton(render-pass …)- Clear values that interact with alpha mode- JavaScript API - The runtime that applies the configuration