Pixi.js
Pixi.js and uno UI can draw to the same canvas by sharing a WebGPU adapter and device. The order of the draw calls determines whether the UI appears in front of or behind the scene.
The examples below assume you are familiar with the basics of uno UI covered in the First Layout section.
Shared setup
Use WebGPURenderer from pixi.js. Pass it the canvas used by uno UI and its adapter and device through the gpu option.
import ResourcesWebGPU from '@uno.build/ui/ResourcesWebGPU'
import UI from '@uno.build/ui/UI'
import { WebGPURenderer } from 'pixi.js'
const canvas = document.querySelector('canvas')
const adapter = await navigator.gpu.requestAdapter()
const resources = await ResourcesWebGPU.create({ canvas, adapter })
const { ui } = await UI.create({ resources })
const renderer = new WebGPURenderer()
await renderer.init({
canvas,
gpu: {
adapter: resources.adapter,
device: resources.device,
},
resolution: window.devicePixelRatio,
backgroundAlpha: 0,
clearBeforeRender: false,
antialias: false,
skipExtensionImports: true,
})Keep antialias: false for this direct canvas composition so Pixi.js draws into the shared canvas texture without resolving a separate multisampled color buffer over the background UI.
The rendering examples below use the stage container and rotating square sprite from the demo. Apply the UI layout and viewport setup before starting the render loop.
Control the draw order
Clear the color at the start of each frame, then preserve it in subsequent draws.
uno UI: load_op
The load_op option of ui.draw() controls what happens to the existing pixels before drawing the UI:
| Value | Effect |
|---|---|
'load' (default) | Keeps existing pixels. Used when calling ui.draw() without options. |
'clear' | Clears the target to transparent black. |
load_op does not choose which layer is in front. The draw order does that. Using 'clear' after drawing the scene erases the scene; using 'load' keeps it visible wherever the UI is transparent.
Pixi.js: clear
The clear option of renderer.render() controls whether Pixi.js clears the color before rendering the scene:
| Value | Effect |
|---|---|
true | Clears the existing color. |
false | Preserves the existing color. |
If clear is omitted, Pixi.js uses clearBeforeRender, which defaults to true but is set to false in the setup above. backgroundAlpha: 0 makes the background transparent; it does not prevent clearing pixels already drawn by uno UI.
UI in front of the scene
Draw the scene first with clear: true, then draw the UI:
requestAnimationFrame(function render(time) {
square.rotation = time / 1000
renderer.render({ container: stage, clear: true })
ui.draw()
requestAnimationFrame(render)
})Pixi.js clears to transparent black and draws the square. uno UI preserves that image and draws the panel over it.
UI behind the scene
Draw the UI first with load_op: 'clear', then render the scene with clear: false:
// uno UI now paints the background, since Pixi.js will not clear the color.
ui.root.style('backgroundColor', '#ffffff')
ui.update()
requestAnimationFrame(function render(time) {
square.rotation = time / 1000
ui.draw({ load_op: 'clear' })
renderer.render({ container: stage, clear: false })
requestAnimationFrame(render)
})uno UI clears the canvas and draws the white background and panel. Pixi.js keeps those pixels and draws the square over them. Using clear: true would erase the UI before drawing the square.
UI behind and in front
For separate background and foreground layouts, create two UI instances using the same resources:
const { ui: background_ui } = await UI.create({ resources })
const { ui: foreground_ui } = await UI.create({ resources })Apply the layout and viewport setup to each UI, then draw the background UI, the scene, and the foreground UI in that order:
requestAnimationFrame(function render(time) {
square.rotation = time / 1000
background_ui.draw({ load_op: 'clear' })
renderer.render({ container: stage, clear: false })
foreground_ui.draw()
requestAnimationFrame(render)
})The background UI starts the frame, Pixi.js draws over it, and the foreground UI draws last. Keep the foreground layout transparent wherever the scene should remain visible.
Demo
This demo uses two UI instances: one for the background and one for the foreground. The foreground UI reuses the React component from the React demo.