BBC's guide to development
  • General

    • About
    • Tools
    • Git(hub)
    • Showpad
    • Hosting
    • Maintenance
    • Security
    • Go live checklist
  • Front-end development

    • Bundlers
    • CSS/SCSS
    • Javascript
    • Vue
    • PHP
    • Mails
    • Dev Faq
  • Functions
  • Mixins
  • General

    • OOP Structure
  • Component Classes

    • Accordion
    • App
    • Component
    • HighwayApp
    • Popup
    • PNG Sequencer
    • Tab
  • Manager Classes

    • BountListenerMgr
    • Cache
    • Configuration
    • InViewStateMgr
    • Instance Manager
    • Event dispatcher
  • Factories

    • SwiperFactory
  • PDF

    • AssetLoader
    • BasePdfDoc
    • TemplatePdfDoc
    • CustomPdfDoc
  • Utility functions

    • canvas
    • Connection Status
    • css
    • dev
    • placeholder
    • dom
    • fetch
    • json
    • object
    • scroll
    • scrollbar
    • spreadsheets
    • string
    • url
  • General

    • ComponentMgr
    • ThreeJsViewer
  • Components

    • ComponentMgr
    • GltfModel
    • Snappable
    • Socket
    • ThreeJsViewer
    • ThreeJsViewerCamera
  • Loaders

    • ConfigurationSerializer
    • GltfBlockParser
  • Utils

    • CanvasInputAdapter
    • CollisionManager
    • SocketGridExpander
    • blender
    • headless
  • General

    • Troubleshooting
    • Legacy
  • Components

    • AssetBar
    • ConfigGenerator
    • ShowpadApp
  • Managers

    • Assets
    • AppsDb
    • Config
  • Utils

    • Connection Status
    • general
    • showpad-interactive
    • showpad-upload
  • Components

    • Accordion
    • BackButton
    • Breadcrumb
    • ByltButton
    • Hamburger
    • Icon
    • Logo
    • Loader
    • Modal
    • Popup
    • Prompt
    • ProgressBar
    • TextLoader
  • Composables

    • useDebugMode
    • useConnectionStatus
  • Utils

    • dom
    • props
  • General

    • General
    • Tracking
  • Components

    • Accordion
    • ActionButton
    • AssetItem
    • AssetList
    • BackButton
    • ConfigGenButton
    • Logo
    • Media
    • Modal
    • Popup
    • Prompt
    • SPButton
    • SPRouterView
    • SPTrackedRouterLink
    • TextLoader
    • View
  • Composables

    • useConnectionStatus
  • Stores

    • useAppsDbStore
    • useBreadcrumbStore
    • useShowpadAPIStore
    • useShowpadSDKStore
    • useSpConfigStore
    • useSpStore
    • useSpTrackingStore
  • The New Kit

    • General
    • Installation & Usage
    • ACF Blocks
    • PHPCS
    • Functions
    • Vite
    • WP Config
    • Staging Deployment
  • Best Practices

    • Page Structure
    • Fonts/Typography
  • Todo
GitHub
  • General

    • About
    • Tools
    • Git(hub)
    • Showpad
    • Hosting
    • Maintenance
    • Security
    • Go live checklist
  • Front-end development

    • Bundlers
    • CSS/SCSS
    • Javascript
    • Vue
    • PHP
    • Mails
    • Dev Faq
  • Functions
  • Mixins
  • General

    • OOP Structure
  • Component Classes

    • Accordion
    • App
    • Component
    • HighwayApp
    • Popup
    • PNG Sequencer
    • Tab
  • Manager Classes

    • BountListenerMgr
    • Cache
    • Configuration
    • InViewStateMgr
    • Instance Manager
    • Event dispatcher
  • Factories

    • SwiperFactory
  • PDF

    • AssetLoader
    • BasePdfDoc
    • TemplatePdfDoc
    • CustomPdfDoc
  • Utility functions

    • canvas
    • Connection Status
    • css
    • dev
    • placeholder
    • dom
    • fetch
    • json
    • object
    • scroll
    • scrollbar
    • spreadsheets
    • string
    • url
  • General

    • ComponentMgr
    • ThreeJsViewer
  • Components

    • ComponentMgr
    • GltfModel
    • Snappable
    • Socket
    • ThreeJsViewer
    • ThreeJsViewerCamera
  • Loaders

    • ConfigurationSerializer
    • GltfBlockParser
  • Utils

    • CanvasInputAdapter
    • CollisionManager
    • SocketGridExpander
    • blender
    • headless
  • General

    • Troubleshooting
    • Legacy
  • Components

    • AssetBar
    • ConfigGenerator
    • ShowpadApp
  • Managers

    • Assets
    • AppsDb
    • Config
  • Utils

    • Connection Status
    • general
    • showpad-interactive
    • showpad-upload
  • Components

    • Accordion
    • BackButton
    • Breadcrumb
    • ByltButton
    • Hamburger
    • Icon
    • Logo
    • Loader
    • Modal
    • Popup
    • Prompt
    • ProgressBar
    • TextLoader
  • Composables

    • useDebugMode
    • useConnectionStatus
  • Utils

    • dom
    • props
  • General

    • General
    • Tracking
  • Components

    • Accordion
    • ActionButton
    • AssetItem
    • AssetList
    • BackButton
    • ConfigGenButton
    • Logo
    • Media
    • Modal
    • Popup
    • Prompt
    • SPButton
    • SPRouterView
    • SPTrackedRouterLink
    • TextLoader
    • View
  • Composables

    • useConnectionStatus
  • Stores

    • useAppsDbStore
    • useBreadcrumbStore
    • useShowpadAPIStore
    • useShowpadSDKStore
    • useSpConfigStore
    • useSpStore
    • useSpTrackingStore
  • The New Kit

    • General
    • Installation & Usage
    • ACF Blocks
    • PHPCS
    • Functions
    • Vite
    • WP Config
    • Staging Deployment
  • Best Practices

    • Page Structure
    • Fonts/Typography
  • Todo
GitHub
  • Headless Utils

Headless Utils

Thumbnail renderer

Utility helper for rendering a Three.js Scene or Object3D to a thumbnail image in a headless way – no viewer UI required. Useful for:

  • Generating block thumbnails for ComponentMgr palettes
  • Precomputing product thumbnails on the client
  • Capturing quick previews from an existing viewer/renderer

All functionality currently lives in a single export: renderThumbnail.

Overview

renderThumbnail renders a scene or object and returns either:

  • a Blob (image/png) – good for uploads / caching
  • a data URL (string) – good for setting img.src
  • a HTMLCanvasElement – good if you want to keep drawing on it

There are two renderer modes:

  • Internal shared renderer (default)
    Creates a THREE.WebGLRenderer once and reuses it across calls. It:

    • Sets size and pixel ratio for you
    • Configures shadow map and color space (sRGB)
    • Temporarily tweaks clear color/alpha based on your options and restores them afterwards
  • External renderer
    You pass in your own THREE.WebGLRenderer. The util:

    • Never mutates its clear color, alpha, or viewport
    • Copies its domElement into a 2D canvas of your requested thumbnail size

Warning

  • Requires a browser-like environment: throws if document is not available.
  • Designed for thumbnails and previews – not a full-frame capture/recording system.

renderThumbnail(options) API

import { renderThumbnail } from '@/utils/headless';

Renders a thumbnail and returns a Promise that resolves to a Blob, data URL string, or HTMLCanvasElement, depending on output.

Options

All options are passed via a single object:

  • object (THREE.Scene | THREE.Object3D, required)
    Root object to render. If it is not a scene, it is cloned and added to a temporary THREE.Scene so the original graph is not mutated.

  • width / height (number, required)
    Thumbnail size in pixels. Used both for:

    • Renderer size / viewport
    • The output canvas dimensions
  • camera (THREE.Camera | (rootScene: THREE.Scene) => THREE.Camera, required)
    Camera to render from:

    • Pass a concrete camera: camera: myCamera
    • Or a resolver: camera: (root) => root.getObjectByName('Camera')

    If the camera has no parent yet, it is temporarily added to the root scene. If it belongs to another scene, a clone is attached instead.

  • output ('blob' | 'dataURL' | 'canvas', default: 'blob')
    Determines the resolved value of the promise:

    • 'blob' → Promise<Blob>
    • 'dataURL' → Promise<string> (PNG data URL)
    • 'canvas' → Promise<HTMLCanvasElement>
  • renderer (THREE.WebGLRenderer, optional)
    External renderer to reuse. When provided:

    • No clear color / alpha / viewport is changed.
    • The renderer’s domElement is drawn into an offscreen <canvas> of your requested width/height.
  • transparent (boolean, default: true)
    Controls whether the background is transparent when you do not supply a backgroundColor:

    • With internal renderer and no backgroundColor:
      • transparent: true → clear alpha 0 (transparent)
      • transparent: false → clear alpha 1 (opaque)
  • preserveDrawingBuffer (boolean, default: true for internal renderer)
    Only used when the helper creates the internal renderer. This ensures toDataURL / toBlob work reliably. Ignored when using an external renderer.

  • backgroundColor (THREE.Color | string | number, optional)
    Background fill color:

    • If set, the internal renderer uses it as clear color.
    • If omitted:
      • And transparent: true → fully transparent background
      • And transparent: false → opaque background using current clear color

Return type

Promise<Blob | string | HTMLCanvasElement>

Depends on the output option.

Behavior details

  • If object is missing, it throws:
    renderThumbnail: "object" is required.
  • If width or height is missing, it throws:
    • renderThumbnail: "width" and "height" are required.
  • If document is not available (non-browser environment), it throws:
    • renderThumbnail: document is not available (must run in a browser environment).
Camera resolution
  • If camera is a function, it receives the root scene (THREE.Scene) and should return a camera (or null).
  • If no camera can be resolved:
    • Logs a warning:
      renderThumbnail: no camera found for thumbnail; returning blank image.
    • Returns a blank canvas (transparent or filled with backgroundColor) in the requested format instead of throwing.
Renderer and aspect handling
  • Internal renderer:

    • A shared THREE.WebGLRenderer instance is created once and reused.
    • Size is set via renderer.setSize(width, height, false).
    • If window.devicePixelRatio exists, setPixelRatio is clamped to a max of 2.
    • Original clear color and alpha are stored, then restored after rendering.
    • For perspective cameras, camera.aspect is temporarily set to width / height and then restored.
  • External renderer:

    • No renderer state (clear color, alpha, viewport) is touched.
    • Helper simply copies renderer.domElement into a fresh 2D canvas at your requested width/height.

Examples

Basic thumbnail as data URL

Generate a square thumbnail from a loaded GLTF scene and show it in an <img> tag:

import { renderThumbnail } from '@/utils/headless';

const thumbnailUrl = await renderThumbnail({
    object: gltf.scene,
    width: 512,
    height: 512,
    camera: (root) => root.getObjectByName('Camera'),
    output: 'dataURL',
    backgroundColor: '#ffffff',
    transparent: false,
});

$img.src = thumbnailUrl;

Using an existing Three.js renderer

Reuse an existing viewer renderer instead of creating a new WebGL context:

import { renderThumbnail } from '@/utils/headless';

const blob = await renderThumbnail({
    object: viewer.scene,
    width: 256,
    height: 256,
    camera: viewer.camera,
    renderer: viewer.renderer,
    output: 'blob',
});

// Upload or cache the blob as needed
uploadThumbnail(blob);

Generating thumbnails for ComponentMgr blocks

Typical pattern: parse blocks with GltfBlockParser, then generate thumbnails for each blocksData entry using renderThumbnail.

import { GltfBlockParser } from '@/configurator';
import { renderThumbnail } from '@/utils/headless';

// After loading your GLTF
GltfBlockParser.copyExtrasToUserData(gltf.scene);
const { blocks, blocksData } = await GltfBlockParser.parse(gltf);

// Generate thumbnails in sequence (or fan out with Promise.all if you prefer)
for (const blockInfo of blocksData) {
    const snappableTemplate = blocks.get(blockInfo.blockId);
    if (!snappableTemplate || blockInfo.hasError) continue;

    // Each Snappable exposes a root object3D you can render
    const object3d = snappableTemplate.object3d;

    const dataUrl = await renderThumbnail({
        object: object3d,
        width: 256,
        height: 256,
        camera: (root) => root.getObjectByName('Camera'),
        output: 'dataURL',
        backgroundColor: '#f5f5f5',
    });

    blockInfo.thumbnailUrl = dataUrl;
}

You can then feed blocksData (with attached thumbnailUrl) straight into your UI palette.

Edit this page
Last Updated: 4/27/26, 12:56 PM
Contributors: Nicolas Jaenen