Skip to content

Three.js Teapot

The Utah teapot rendered with Three.js, with live Adwaita-styled controls for tessellation level, body / lid / bottom toggles, and material switching. Ported from refs/three/examples/webgl_geometry_teapot.html.

PillarWhat Three.js needs
@gjsify/webglFull WebGL 2.0 surface — Three’s renderer reaches for VAOs, uniform buffer objects, texStorage2D, drawElementsInstanced. All routed through the gwebgl Vala bridge → libepoxy → GLES 3.2.
@gjsify/dom-elementsHTMLCanvasElement, requestAnimationFrame, ResizeObserver, OrbitControls mouse events
@gjsify/event-bridgeMouse drag → camera orbit
@gjsify/adwaita-webBrowser embed’s control panel styling
Adwaita widgets (GJS)Adw.PreferencesGroup + Adw.SwitchRow + Adw.SpinRow for the same controls
gjsify showcase three-geometry-teapot

A GTK4 window opens with an Adw.ToolbarView shell: the toolbar holds the controls (tessellation 1-20, body/lid/bottom switches, material dropdown), the content area is the WebGL canvas. Drag with the mouse to orbit the camera; scroll to zoom.

import { mount } from '@gjsify/example-dom-three-geometry-teapot/browser';
mount(document.getElementById('app')!);

Same shared scene logic. The browser embed renders the same controls through @gjsify/adwaita-web’s custom elements so the visual story is identical.

showcases/dom/three-geometry-teapot/

  • src/three-demo.ts — the Three.js scene (shared between targets, no GJS-specific imports)
  • src/gjs/gjs.tsAdw.Application entry point that boots the window
  • src/gjs/teapot-window.ts + src/gjs/teapot-window.blpAdw.ApplicationWindow with Blueprint UI definitions
  • src/browser/browser.ts — DOM mount + Adwaita-web wiring
  • src/browser/browser-main.ts — standalone browser entry point (fullscreen demo)
  • src/assets/uv_grid_opengl.jpg + src/assets/pisa/ — UV grid texture and Pisa cubemap (shipped as npm assets via exports['./assets/*'])

@gjsify/webgl’s Vala bridge maps each WebGL call into libepoxy’s GLES 3.2 surface — but Three.js does NOT target GLES, it targets desktop WebGL. The fact that it runs unmodified is the load-bearing claim: the bridge handles every format / type / blit / buffer-storage difference between WebGL and GLES, so consumer code stays browser-shaped.

When new Three.js features land (e.g. WebGPU paths, new post-processing passes), this showcase is one of the first regression targets — the matrix of WebGL calls Three reaches for is the broadest realistic surface available.

  • three-postprocessing-pixel — same engine, different rendering pipeline (post-FX framebuffers + custom shaders)
  • Bridge widgets pattern — covers the WebGLBridge lifecycle, including the resize → reframe flow
  • @gjsify/webgl — the package itself, where every new Three.js requirement gets implemented