Skip to content

Quick Start

This guide creates the complete CustomForge Workbench with the built-in demonstration product, so no model or texture files are required yet

1 Create a mount element

html
<div id="app"></div>

The Workbench must have a measurable height

css
html,
body,
#app {
  height: 100%;
  margin: 0;
}

2 Create the Workbench

ts
import { createWorkbench } from 'customforge/workbench'
import 'customforge/style.css'

const workbench = await createWorkbench({
  container: '#app',
})

workbench.customizer.addText({
  text: 'CustomForge',
  x: 690,
  y: 320,
  width: 220,
  color: '#182023',
})
workbench.customizer.clearSelection()

createWorkbench() resolves after the editor, viewer, product, and live texture bridge are ready

Omitting fontSize uses the 22px default

Because no product was provided, this example uses the bundled cup_decal_small_margins.glb cup and its PrintArea Mesh

3 Try the editor

The initial Workbench provides

  • A 2D texture editor on the left
  • A layer panel for object ordering and state
  • A live 3D product preview on the right
  • Text and image dialogs
  • An Office-style contextual formatting bar for selected text
  • Undo, redo, Design JSON, product loading, PNG export, and camera controls

Drag, resize, or rotate the text on the 2D canvas and the 3D preview updates immediately

4 Load your own product

Once you have a UV-mapped model, pass its remote URL during initialization

ts
const workbench = await createWorkbench({
  container: '#app',
  product: {
    modelUrl: 'https://cdn.example.com/products/mug.glb',
    textureUrl: 'https://cdn.example.com/products/mug-base.png',
    surfaceMesh: 'PrintArea',
    textureFlipY: false,
  },
})

textureUrl is optional, while modelUrl must point to a model with valid UV coordinates

See Product Assets before exporting a model for CustomForge

5 Release resources

Each instance owns DOM listeners, Fabric state, WebGL resources, and observers

Destroy it when the page or host component is no longer in use

ts
window.addEventListener('beforeunload', () => workbench.destroy(), {
  once: true,
})

In Vue, React, or another component framework, call destroy() from the component unmount lifecycle instead

Where to continue