- Plane position
- Plane UV
- Plane Mutability
- Cube
- Multiple Planes
- Other Shapes
- DOM Sync
- Proxy Objects
- Vue Integration for Proxy Objects
- TS Conversion
- Scroll Hook
- Mouse Hook
- Image Plane
- Video Plane
- Bend Plane
- Deform Gradient Plane
- WGSL Bomber
- Tension Shader
- Post Processing
- Compute Shaders
- Frame Buffer Tools
- Lights
- VR
- Models
- Animations (gsap?)
- Timeline (gsap?)
- Groups
- Many Models Performance (instanced)
- Materials
- Physics
- Particles
- Audio
- HMR
Minimal example combining multi-shader pipelines with optional post-processing using the high-level Scene helper.
import { getMemory, createScene, cube, uTime, gpuCamera } from 'moonbow'
// 1. Acquire memory (device + canvas + user uniforms)
const canvas = document.querySelector('canvas')!
const memory = await getMemory({
canvas,
shader: '', // base placeholder when using multi-shader; each pipeline provides its own
model: true,
uniforms: ({ device }) => ({
time: uTime(device, 0.5),
camera: gpuCamera(device) // assuming gpuCamera exported
})
})
// 2. Define WGSL shaders (vertexMain / fragmentMain entry points required)
import basicWGSL from './shaders/basic.wgsl?raw'
import altWGSL from './shaders/gradient.wgsl?raw'
import postWGSL from './shaders/postprocessFlexible.wgsl?raw'
// 3. Create scene (multi-shader + optional post-process)
const scene = createScene({
memory,
shaders: [
{ label: 'basic', shader: basicWGSL },
{ label: 'alt', shader: altWGSL }
],
postProcess: {
postProcessShader: postWGSL
}
})
// 4. Render frame: supply render calls referencing pipeline label or index
function frame() {
// Update dynamic uniforms before rendering
Object.values(memory.uniforms).forEach((u) => u.update())
scene.render([
{
pipeline: 'basic',
renderFunction: (pass) => {
// Example draw call (matching geometry bound in shader); adapt as needed
pass.draw(36) // 36 vertices for a cube if using built-in attribute logic
}
}
])
requestAnimationFrame(frame)
}
requestAnimationFrame(frame)
// 5. Handle resize
window.addEventListener('resize', () => {
canvas.width = canvas.clientWidth * devicePixelRatio
canvas.height = canvas.clientHeight * devicePixelRatio
scene.resize()
})
// 6. Cleanup when removing scene (SPA route change, etc.)
// scene.dispose()Key methods:
scene.render(calls)– multi-pipeline render (with post-processing if configured)scene.resize()– revalidates depth & offscreen targetsscene.dispose()– destroys cached textures & underlying pipelines
Uniform Management Tips:
- Call each uniform's
update()per frame if time-varying. - Use
pipeline.updateAllBuffers()when working directly with a single pipeline instance.
Post-Processing:
-
Provide your own WGSL via
postProcessShaderor usecreateAutoPostProcessPipelineindirectly viapostProcess: { auto: true }(see code for generation behavior).
- orillusion
- performance
- codelab
- caniuse
- surma
- metal
- CIS 565 GPU Programming
- vulkan
- firebase
- architecture
- best webgl intro
- bookofshaders
-
24 cores is the current upper limit for CPU due to exponential heat mangagment and complexity: M2 Ultra, I9 Intel
-
RTX 4080 has 9700 cores
-
TPU (Tensor GPU) vs DPU (data CPU) vs QPU (bits vs cubits)
-
"Despite the core’s frequency, getting data from memory (or pixels from textures) still takes relatively long — Fabian says it takes a couple hundred clock cycles. These couple hundred cycles could be spent on computation instead. To make use of these otherwise idle cycles, each EU is heavily oversubscribed with work. Whenever an EU would end up idling (e.g. to wait for a value from memory), it instead switches to another work item and will only switch back once the new work item needs to wait for something. This is the key trick how GPUs optimize for throughput at the cost of latency: Individual work items will take longer as a switch to another work item might stop execution for longer than necessary, but the overall utilization is higher and results in a higher throughput. The GPU strives to always have work queued up to keep EUs busy at all times." - source