customforge 0.1.0-alpha.0 → 0.1.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +61 -27
- package/LICENSE +201 -201
- package/LICENSES/NunitoSans-OFL.txt +93 -0
- package/README.md +339 -152
- package/README.zh-CN.md +337 -152
- package/dist/NunitoSans-Variable.ttf +0 -0
- package/dist/ProductCustomizer-rMRyWe7L.js +1624 -0
- package/dist/ProductCustomizer-rMRyWe7L.js.map +1 -0
- package/dist/core/design.d.ts.map +1 -1
- package/dist/core/types.d.ts +35 -4
- package/dist/core/types.d.ts.map +1 -1
- package/dist/customizer/ProductCustomizer.d.ts +78 -0
- package/dist/customizer/ProductCustomizer.d.ts.map +1 -1
- package/dist/editor/DesignEditor.d.ts +108 -6
- package/dist/editor/DesignEditor.d.ts.map +1 -1
- package/dist/editor/DesignHistory.d.ts +27 -0
- package/dist/editor/DesignHistory.d.ts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1108
- package/dist/index.js.map +1 -1
- package/dist/style.css +1330 -11
- package/dist/workbench/CustomForgeWorkbench.d.ts +128 -0
- package/dist/workbench/CustomForgeWorkbench.d.ts.map +1 -0
- package/dist/workbench/assets/catalog.d.ts +8 -0
- package/dist/workbench/assets/catalog.d.ts.map +1 -0
- package/dist/workbench/config.d.ts +55 -0
- package/dist/workbench/config.d.ts.map +1 -0
- package/dist/workbench/icons.d.ts +4 -0
- package/dist/workbench/icons.d.ts.map +1 -0
- package/dist/workbench/index.d.ts +25 -0
- package/dist/workbench/index.d.ts.map +1 -0
- package/dist/workbench/template.d.ts +3 -0
- package/dist/workbench/template.d.ts.map +1 -0
- package/dist/workbench/types.d.ts +294 -0
- package/dist/workbench/types.d.ts.map +1 -0
- package/dist/workbench.js +1920 -0
- package/dist/workbench.js.map +1 -0
- package/package.json +8 -5
package/README.md
CHANGED
|
@@ -1,23 +1,28 @@
|
|
|
1
|
-
<div align="center">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
<p>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
<
|
|
15
|
-
</
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="./src/workbench/assets/CustomForgeLogo.png" alt="CustomForge Logo" width="136">
|
|
4
|
+
|
|
5
|
+
<h1>CustomForge</h1>
|
|
6
|
+
|
|
7
|
+
<hr>
|
|
8
|
+
|
|
9
|
+
<p><strong>Turn a 2D texture canvas into a live 3D product preview</strong></p>
|
|
10
|
+
|
|
11
|
+
<p>A lightweight, framework-agnostic toolkit for building browser-based product customization experiences with Fabric.js and Three.js</p>
|
|
12
|
+
|
|
13
|
+
<p>
|
|
14
|
+
<strong>English</strong>
|
|
15
|
+
<span> · </span>
|
|
16
|
+
<a href="./README.zh-CN.md">简体中文</a>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<p>
|
|
20
|
+
<img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-strict-2563EB?style=flat-square&logo=typescript&logoColor=white&labelColor=1F2937">
|
|
21
|
+
<img alt="Vite" src="https://img.shields.io/badge/Vite-8-7C3AED?style=flat-square&logo=vite&logoColor=white&labelColor=1F2937">
|
|
22
|
+
<img alt="Three.js" src="https://img.shields.io/badge/Three.js-r185-27272A?style=flat-square&logo=threedotjs&logoColor=white&labelColor=1F2937">
|
|
23
|
+
<img alt="Fabric.js" src="https://img.shields.io/badge/Fabric.js-7-BE185D?style=flat-square&labelColor=1F2937">
|
|
24
|
+
<img alt="License" src="https://img.shields.io/badge/License-Apache%202.0-0F766E?style=flat-square&logo=apache&logoColor=white&labelColor=1F2937">
|
|
25
|
+
</p>
|
|
21
26
|
|
|
22
27
|
</div>
|
|
23
28
|
|
|
@@ -32,15 +37,19 @@ CustomForge connects a familiar 2D design surface to a UV-mapped 3D model:
|
|
|
32
37
|
- Preview every canvas change on a 3D product in real time
|
|
33
38
|
- Load remote GLB/GLTF models and optional base textures
|
|
34
39
|
- Select the customizable surface by mesh name
|
|
35
|
-
- Rotate and zoom the 3D preview with OrbitControls
|
|
36
|
-
- Export the composed texture as a PNG
|
|
37
|
-
- Save and restore editable objects through versioned Design JSON
|
|
40
|
+
- Rotate and zoom the 3D preview with OrbitControls
|
|
41
|
+
- Export the composed texture as a PNG
|
|
42
|
+
- Save and restore editable objects through versioned Design JSON
|
|
43
|
+
- Organize objects through names, visibility, locking, and layer order
|
|
44
|
+
- Undo and redo design changes through snapshot history
|
|
45
|
+
- Use configurable typography, background, and decorative asset Dialogs
|
|
46
|
+
- Adapt the default Workbench with branding, labels, theme tokens, and icons
|
|
38
47
|
|
|
39
48
|
The included workbench starts with a procedural cup, so the project works immediately without external assets
|
|
40
49
|
|
|
41
|
-
## Repository Development
|
|
42
|
-
|
|
43
|
-
Requirements: Node.js 22+ and pnpm 11+
|
|
50
|
+
## Repository Development
|
|
51
|
+
|
|
52
|
+
Requirements: Node.js 22+ and pnpm 11+
|
|
44
53
|
|
|
45
54
|
```bash
|
|
46
55
|
pnpm install
|
|
@@ -49,43 +58,59 @@ pnpm dev
|
|
|
49
58
|
|
|
50
59
|
Open the URL printed by Vite
|
|
51
60
|
|
|
52
|
-
The built-in demo appears with a UV workspace on the left and a live 3D preview on the right
|
|
53
|
-
|
|
54
|
-
## npm Alpha Package
|
|
55
|
-
|
|
56
|
-
CustomForge is
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
```powershell
|
|
61
|
-
pnpm add customforge@alpha
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
pnpm
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
61
|
+
The built-in demo appears with a UV workspace on the left and a live 3D preview on the right
|
|
62
|
+
|
|
63
|
+
## npm Alpha Package
|
|
64
|
+
|
|
65
|
+
CustomForge is available from the npm Registry under the `alpha` dist-tag and the API and Design JSON Schema may change between alpha versions
|
|
66
|
+
|
|
67
|
+
Install the current public alpha with:
|
|
68
|
+
|
|
69
|
+
```powershell
|
|
70
|
+
pnpm add customforge@alpha
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Fabric.js and Three.js are installed automatically as transitive dependencies
|
|
74
|
+
|
|
75
|
+
pnpm may report that the optional native `canvas` build script was ignored
|
|
76
|
+
|
|
77
|
+
CustomForge runs in the browser and does not use Node native canvas, so `pnpm approve-builds` is not required
|
|
78
|
+
|
|
79
|
+
Consumer projects can explicitly acknowledge this browser-only choice in `package.json`:
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"pnpm": {
|
|
84
|
+
"ignoredBuiltDependencies": ["canvas"]
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Package page: [npmjs.com/package/customforge](https://www.npmjs.com/package/customforge)
|
|
90
|
+
|
|
91
|
+
For repository-independent verification before publishing, build and create the local package from the repository root:
|
|
92
|
+
|
|
93
|
+
```powershell
|
|
94
|
+
pnpm pack:local
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The command builds JavaScript, TypeScript declarations, and public styles, checks the npm file list, and creates:
|
|
98
|
+
|
|
99
|
+
```text
|
|
100
|
+
customforge-0.1.0-alpha.2.tgz
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Install that local package in an independent Vite TypeScript project:
|
|
104
|
+
|
|
105
|
+
```powershell
|
|
106
|
+
pnpm add D:\projects\3DRendering\core_code\customforge-0.1.0-alpha.2.tgz
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The checked-in `examples/npm-consumer` project imports CustomForge only through this `.tgz`. Run `pnpm install --ignore-workspace` in that directory so pnpm installs it independently from the parent workspace
|
|
85
110
|
|
|
86
111
|
## Load Your Product
|
|
87
112
|
|
|
88
|
-
Choose **Load
|
|
113
|
+
Choose **Load product** in the demo and provide:
|
|
89
114
|
|
|
90
115
|
| Field | Purpose |
|
|
91
116
|
| --- | --- |
|
|
@@ -103,22 +128,22 @@ The optional texture image is the visual base layer, not a replacement for model
|
|
|
103
128
|
>
|
|
104
129
|
> A blocked or canvas-tainting resource may fail to load and can prevent PNG export
|
|
105
130
|
|
|
106
|
-
## Basic Usage
|
|
107
|
-
|
|
108
|
-
The framework-independent Library entry can be mounted into any two DOM containers:
|
|
109
|
-
|
|
110
|
-
CustomForge is browser-only and must be initialized after its DOM containers are available
|
|
111
|
-
|
|
112
|
-
The editor and viewer require two different containers; call `destroy()` when the page, host component, or instance is no longer in use to release Fabric, WebGL, observer, and event resources
|
|
131
|
+
## Basic Usage
|
|
132
|
+
|
|
133
|
+
The framework-independent Library entry can be mounted into any two DOM containers:
|
|
134
|
+
|
|
135
|
+
CustomForge is browser-only and must be initialized after its DOM containers are available
|
|
136
|
+
|
|
137
|
+
The editor and viewer require two different containers; call `destroy()` when the page, host component, or instance is no longer in use to release Fabric, WebGL, observer, and event resources
|
|
113
138
|
|
|
114
139
|
```html
|
|
115
140
|
<div id="texture-editor"></div>
|
|
116
141
|
<div id="product-viewer"></div>
|
|
117
142
|
```
|
|
118
143
|
|
|
119
|
-
```ts
|
|
120
|
-
import { createCustomizer } from 'customforge'
|
|
121
|
-
import 'customforge/style.css'
|
|
144
|
+
```ts
|
|
145
|
+
import { createCustomizer } from 'customforge'
|
|
146
|
+
import 'customforge/style.css'
|
|
122
147
|
|
|
123
148
|
const customizer = await createCustomizer({
|
|
124
149
|
editor: '#texture-editor',
|
|
@@ -141,64 +166,222 @@ customizer.addText({
|
|
|
141
166
|
color: '#172126',
|
|
142
167
|
})
|
|
143
168
|
|
|
144
|
-
await customizer.addImage({
|
|
145
|
-
src: 'https://example.com/logo.png',
|
|
146
|
-
x: 720,
|
|
147
|
-
y: 240,
|
|
148
|
-
width: 220,
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
window.addEventListener('beforeunload', () => customizer.destroy(), {
|
|
152
|
-
once: true,
|
|
153
|
-
})
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
The public package uses the same root and style imports as the local `.tgz`; pin an exact alpha version when reproducible installs are required
|
|
157
|
-
|
|
158
|
-
##
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
169
|
+
await customizer.addImage({
|
|
170
|
+
src: 'https://example.com/logo.png',
|
|
171
|
+
x: 720,
|
|
172
|
+
y: 240,
|
|
173
|
+
width: 220,
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
window.addEventListener('beforeunload', () => customizer.destroy(), {
|
|
177
|
+
once: true,
|
|
178
|
+
})
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
The public package uses the same root and style imports as the local `.tgz`; pin an exact alpha version when reproducible installs are required
|
|
182
|
+
|
|
183
|
+
## Ready-made Workbench
|
|
184
|
+
|
|
185
|
+
Use the optional Workbench entry when a complete default interface is preferable to building controls from scratch
|
|
186
|
+
|
|
187
|
+
The host element must have an explicit height so the design surface, layers, and 3D preview can measure their available space
|
|
188
|
+
|
|
189
|
+
```html
|
|
190
|
+
<div id="customforge-workbench" style="height: 720px"></div>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
import { createWorkbench } from 'customforge/workbench'
|
|
195
|
+
import 'customforge/style.css'
|
|
196
|
+
|
|
197
|
+
const workbench = await createWorkbench({
|
|
198
|
+
container: '#customforge-workbench',
|
|
199
|
+
product: {
|
|
200
|
+
modelUrl: 'https://example.com/product.glb',
|
|
201
|
+
surfaceMesh: 'PrintArea',
|
|
202
|
+
},
|
|
203
|
+
features: {
|
|
204
|
+
presetBackgrounds: true,
|
|
205
|
+
presetElements: true,
|
|
206
|
+
},
|
|
207
|
+
layout: {
|
|
208
|
+
header: true,
|
|
209
|
+
layers: true,
|
|
210
|
+
},
|
|
211
|
+
branding: {
|
|
212
|
+
logoUrl: '/brand/logo.png',
|
|
213
|
+
title: 'Studio',
|
|
214
|
+
subtitle: 'Product personalization',
|
|
215
|
+
},
|
|
216
|
+
labels: {
|
|
217
|
+
addText: 'Typography',
|
|
218
|
+
addImage: 'Artwork',
|
|
219
|
+
},
|
|
220
|
+
theme: {
|
|
221
|
+
accent: '#0057b8',
|
|
222
|
+
accentHover: '#003f87',
|
|
223
|
+
accentContrast: '#ffffff',
|
|
224
|
+
},
|
|
225
|
+
assets: {
|
|
226
|
+
backgrounds: [
|
|
227
|
+
{ id: 'floral', name: 'Floral', url: '/presets/floral.png' },
|
|
228
|
+
],
|
|
229
|
+
elements: [
|
|
230
|
+
{ id: 'flower', name: 'Flower', url: '/presets/flower.png' },
|
|
231
|
+
],
|
|
232
|
+
},
|
|
233
|
+
})
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
The bundled CustomForge logo is used by default and can be replaced or hidden through `branding`
|
|
237
|
+
|
|
238
|
+
`labels` replaces visible Workbench copy, `theme` maps to scoped CSS variables, and `icons` can disable built-in icons or replace individual semantic icons with image URLs
|
|
239
|
+
|
|
240
|
+
The default UI font stack prefers the rounded `Nunito Sans` family and falls back to system sans-serif fonts
|
|
241
|
+
|
|
242
|
+
CustomForge bundles the font asset and does not fetch third-party font services at runtime
|
|
243
|
+
|
|
244
|
+
Text and image commands open focused Dialogs instead of immediately mutating the canvas
|
|
245
|
+
|
|
246
|
+
- The text Dialog includes an input, color control, and replaceable typography presets
|
|
247
|
+
- The image Dialog includes local upload, background presets, and decorative element presets
|
|
248
|
+
- A design background replaces the previous design background, fills the canvas, starts locked at the bottom layer, and persists in Design JSON
|
|
249
|
+
|
|
250
|
+
Feature and layout switches can also be changed after initialization
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
workbench.setFeature('addText', true)
|
|
254
|
+
workbench.setLayout('header', true)
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
| Feature switch | Controls |
|
|
258
|
+
| --- | --- |
|
|
259
|
+
| `addText`, `addImage`, `deleteSelection` | Object Dialogs and deletion |
|
|
260
|
+
| `undoRedo` | Undo and redo buttons plus Workbench keyboard shortcuts |
|
|
261
|
+
| `saveDesign`, `loadDesign` | Design JSON actions |
|
|
262
|
+
| `loadRemoteProduct`, `exportTexture`, `resetView` | Product and output actions |
|
|
263
|
+
| `reorderObjects`, `toggleObjectVisibility`, `lockObjects`, `renameObjects` | Layer management |
|
|
264
|
+
| `presetBackgrounds`, `presetElements` | Image Dialog preset tabs |
|
|
265
|
+
|
|
266
|
+
| Layout switch | Region |
|
|
267
|
+
| --- | --- |
|
|
268
|
+
| `header` | Brand and global product actions |
|
|
269
|
+
| `editorHeader`, `viewerHeader` | Workspace panel headings |
|
|
270
|
+
| `toolbar` | Design tool controls |
|
|
271
|
+
| `layers` | Object layer panel |
|
|
272
|
+
| `status` | Runtime status and object count |
|
|
273
|
+
|
|
274
|
+
All feature and layout values default to `true`
|
|
275
|
+
|
|
276
|
+
Feature switches only control the built-in Workbench controls and do not remove methods from `workbench.customizer`
|
|
277
|
+
|
|
278
|
+
Theme values are intended for coherent product-level styling rather than per-button color configuration
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
const workbench = await createWorkbench({
|
|
282
|
+
container: '#customforge-workbench',
|
|
283
|
+
icons: {
|
|
284
|
+
enabled: true,
|
|
285
|
+
sources: {
|
|
286
|
+
addText: '/icons/typography.svg',
|
|
287
|
+
exportTexture: null,
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
textPresets: [
|
|
291
|
+
{
|
|
292
|
+
id: 'brand-display',
|
|
293
|
+
name: 'Brand display',
|
|
294
|
+
fontFamily: 'Arial',
|
|
295
|
+
fontSize: 72,
|
|
296
|
+
width: 460,
|
|
297
|
+
color: '#17191c',
|
|
298
|
+
},
|
|
299
|
+
],
|
|
300
|
+
})
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## Design JSON
|
|
304
|
+
|
|
305
|
+
`saveDesign()` returns a Library-owned, JSON-safe document instead of exposing Fabric.js serialization. `loadDesign()` validates unknown input and restores the editable object stack asynchronously:
|
|
306
|
+
|
|
307
|
+
```ts
|
|
308
|
+
const design = customizer.saveDesign()
|
|
309
|
+
localStorage.setItem('customforge-design', JSON.stringify(design))
|
|
310
|
+
|
|
311
|
+
const savedDesign = localStorage.getItem('customforge-design')
|
|
312
|
+
if (savedDesign) {
|
|
313
|
+
await customizer.loadDesign(JSON.parse(savedDesign))
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
The current Schema version is `1`. It stores the logical canvas size and the text and image objects in back-to-front render order, including stable object IDs, names, visibility, locking, image roles, and center-based transforms
|
|
318
|
+
|
|
319
|
+
Design JSON intentionally excludes the product model, target mesh, and base texture. A document can only be loaded into an editor with exactly the same logical width and height
|
|
320
|
+
|
|
321
|
+
An image with `role: 'background'` is a design object rather than the product base texture. Only one is allowed, it must be the first object, and older version 1 documents without `role` continue to load as ordinary image elements
|
|
322
|
+
|
|
323
|
+
Loading is transactional: the current design remains unchanged unless the document validates and every referenced image loads successfully. Blob URL images are converted to Data URLs when added; remote image URLs remain URLs and must continue to satisfy browser CORS requirements when restored
|
|
324
|
+
|
|
325
|
+
The Schema is still an alpha contract and may change in later alpha versions
|
|
326
|
+
|
|
327
|
+
## Undo and Redo
|
|
328
|
+
|
|
329
|
+
History is enabled in both the headless core and Workbench and defaults to 50 undo steps
|
|
330
|
+
|
|
331
|
+
Set `historyLimit` in `createCustomizer` or `createWorkbench` options to change the retained undo depth
|
|
332
|
+
|
|
333
|
+
```ts
|
|
334
|
+
if (customizer.canUndo()) {
|
|
335
|
+
await customizer.undo()
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
await customizer.redo()
|
|
339
|
+
customizer.clearHistory()
|
|
340
|
+
|
|
341
|
+
const stop = customizer.on('historychange', ({ canUndo, canRedo }) => {
|
|
342
|
+
console.log({ canUndo, canRedo })
|
|
343
|
+
})
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
History covers object creation, deletion, canvas transforms, text edits, layer order, names, visibility, locking, and Design JSON loading
|
|
347
|
+
|
|
348
|
+
Workbench also supports `Ctrl` or `Cmd` + `Z`, `Ctrl` or `Cmd` + `Shift` + `Z`, and `Ctrl` + `Y` while focus is outside form fields
|
|
349
|
+
|
|
350
|
+
Successful product replacement keeps the current design but starts a new history baseline
|
|
351
|
+
|
|
352
|
+
## Instance API
|
|
181
353
|
|
|
182
354
|
| Method | Description |
|
|
183
355
|
| --- | --- |
|
|
184
|
-
| `addText(options)` | Add and select editable text, constrained to the canvas |
|
|
185
|
-
| `addImage(options)` | Load and select an
|
|
186
|
-
| `
|
|
187
|
-
| `
|
|
188
|
-
| `
|
|
189
|
-
| `
|
|
356
|
+
| `addText(options)` | Add and select editable text, constrained to the canvas |
|
|
357
|
+
| `addImage(options)` | Load and select an element or replace the design background |
|
|
358
|
+
| `getObjects()` | Return the current objects in back-to-front layer order |
|
|
359
|
+
| `getSelectedObjectIds()` | Return stable IDs for the current selection |
|
|
360
|
+
| `selectObject(id)` | Select a visible object by stable ID |
|
|
361
|
+
| `removeObject(id)` | Remove an object by stable ID |
|
|
362
|
+
| `moveObject(id, index)` | Move an object to a zero-based layer index |
|
|
363
|
+
| `renameObject(id, name)` | Change the object name shown in layer tools |
|
|
364
|
+
| `setObjectVisibility(id, visible)` | Include or exclude an object from rendering |
|
|
365
|
+
| `setObjectLocked(id, locked)` | Lock or unlock canvas transformations |
|
|
366
|
+
| `deleteSelected()` | Remove the active object or selection |
|
|
367
|
+
| `saveDesign()` | Return the current versioned Design JSON document |
|
|
368
|
+
| `loadDesign(value)` | Validate and transactionally restore Design JSON |
|
|
369
|
+
| `canUndo()`, `canRedo()` | Query the current history directions |
|
|
370
|
+
| `undo()`, `redo()` | Restore the previous or next design snapshot |
|
|
371
|
+
| `clearHistory()` | Make the current design the new history baseline |
|
|
372
|
+
| `loadProduct(product)` | Replace the model, base texture, and target mesh |
|
|
190
373
|
| `exportTexture(filename?)` | Download the composed texture as PNG |
|
|
191
374
|
| `resetView()` | Restore the default 3D camera position |
|
|
192
375
|
| `on(event, listener)` | Subscribe to instance events; returns an unsubscribe function |
|
|
193
376
|
| `destroy()` | Release DOM events, Fabric state, and WebGL resources |
|
|
194
377
|
|
|
195
|
-
Available events are `ready`, `change`, `selectionchange`, `status`, and `error`
|
|
196
|
-
|
|
197
|
-
The initial alpha stability boundary is limited to the methods above, `createCustomizer`, `ProductCustomizer`, and the configuration, event, and Design JSON types exported from
|
|
198
|
-
|
|
199
|
-
`ProductCustomizer` does not expose its Fabric.js editor or Three.js viewer instances; consumers interact through the facade API
|
|
200
|
-
|
|
201
|
-
Imports from `core`, `editor`, `viewer`, `bridge`, or any other undeclared package subpath are unsupported
|
|
378
|
+
Available events are `ready`, `change`, `selectionchange`, `historychange`, `status`, and `error`
|
|
379
|
+
|
|
380
|
+
The initial alpha stability boundary is limited to the methods above, `createCustomizer`, `ProductCustomizer`, the `customforge/workbench` entry, and the configuration, event, Workbench, and Design JSON types exported from declared package entries
|
|
381
|
+
|
|
382
|
+
`ProductCustomizer` does not expose its Fabric.js editor or Three.js viewer instances; consumers interact through the facade API
|
|
383
|
+
|
|
384
|
+
Imports from `core`, `editor`, `viewer`, `bridge`, or any other undeclared package subpath are unsupported
|
|
202
385
|
|
|
203
386
|
## Architecture
|
|
204
387
|
|
|
@@ -223,7 +406,7 @@ ProductCustomizer
|
|
|
223
406
|
|
|
224
407
|
`ProductCustomizer` coordinates the modules while keeping Fabric.js and Three.js details behind a small instance API
|
|
225
408
|
|
|
226
|
-
The demo
|
|
409
|
+
The optional Workbench and demo use Vanilla TypeScript; the core does not depend on Vue, React, or another UI framework
|
|
227
410
|
|
|
228
411
|
## Model Contract
|
|
229
412
|
|
|
@@ -240,36 +423,37 @@ The built-in demo follows the same `PrintArea` mesh convention
|
|
|
240
423
|
## Project Structure
|
|
241
424
|
|
|
242
425
|
```text
|
|
243
|
-
src/
|
|
244
|
-
|-- bridge/ Canvas and Three.js texture synchronization
|
|
245
|
-
|-- core/ Public types, configuration, and DOM helpers
|
|
246
|
-
|-- customizer/ Public instance orchestration
|
|
247
|
-
|-- demo/ Runnable workbench UI
|
|
248
|
-
|-- editor/ Fabric.js design surface
|
|
249
|
-
|-- style.css Public Library style entry
|
|
250
|
-
|-- styles/
|
|
251
|
-
|-- viewer/ Three.js product preview
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
426
|
+
src/
|
|
427
|
+
|-- bridge/ Canvas and Three.js texture synchronization
|
|
428
|
+
|-- core/ Public types, configuration, and DOM helpers
|
|
429
|
+
|-- customizer/ Public instance orchestration
|
|
430
|
+
|-- demo/ Runnable workbench UI
|
|
431
|
+
|-- editor/ Fabric.js design surface and snapshot history
|
|
432
|
+
|-- style.css Public Library style entry
|
|
433
|
+
|-- styles/ Core and Workbench styles
|
|
434
|
+
|-- viewer/ Three.js product preview
|
|
435
|
+
|-- workbench/ Configurable UI, Dialogs, icons, and preset assets
|
|
436
|
+
`-- index.ts Framework-independent source entry
|
|
437
|
+
|
|
438
|
+
examples/
|
|
439
|
+
`-- npm-consumer/ Independent local .tgz consumer
|
|
440
|
+
|
|
441
|
+
scripts/
|
|
442
|
+
`-- verify-package.mjs npm file and artifact boundary checks
|
|
443
|
+
```
|
|
260
444
|
|
|
261
445
|
## Development Commands
|
|
262
446
|
|
|
263
447
|
```bash
|
|
264
|
-
pnpm check # TypeScript project check
|
|
265
|
-
pnpm test # Unit tests
|
|
266
|
-
pnpm build # Type-check and production build
|
|
267
|
-
pnpm build:lib # Build ESM, declarations, and
|
|
268
|
-
pnpm verify:package # Check dist and the npm file list
|
|
269
|
-
pnpm pack:local # Build, verify, and create the local .tgz
|
|
270
|
-
pnpm release:check # Run checks, tests, package build, verification, and local pack
|
|
271
|
-
pnpm preview # Preview the production build
|
|
272
|
-
```
|
|
448
|
+
pnpm check # TypeScript project check
|
|
449
|
+
pnpm test # Unit tests
|
|
450
|
+
pnpm build # Type-check and production build
|
|
451
|
+
pnpm build:lib # Build core and Workbench ESM, declarations, and styles
|
|
452
|
+
pnpm verify:package # Check dist and the npm file list
|
|
453
|
+
pnpm pack:local # Build, verify, and create the local .tgz
|
|
454
|
+
pnpm release:check # Run checks, tests, package build, verification, and local pack
|
|
455
|
+
pnpm preview # Preview the production build
|
|
456
|
+
```
|
|
273
457
|
|
|
274
458
|
## Current Scope
|
|
275
459
|
|
|
@@ -277,16 +461,17 @@ This is an early technical prototype
|
|
|
277
461
|
|
|
278
462
|
The public API and design document format are not stable yet
|
|
279
463
|
|
|
280
|
-
The current milestone intentionally focuses on one texture and one customizable mesh
|
|
281
|
-
|
|
282
|
-
Public npm releases use the `alpha` dist-tag until the API and Design JSON contract are ready for a more stable channel
|
|
283
|
-
|
|
284
|
-
Multi-surface products,
|
|
464
|
+
The current milestone intentionally focuses on one texture and one customizable mesh
|
|
465
|
+
|
|
466
|
+
Public npm releases use the `alpha` dist-tag until the API and Design JSON contract are ready for a more stable channel
|
|
467
|
+
|
|
468
|
+
Multi-surface products, advanced alignment tools, and framework adapters are not implemented yet
|
|
285
469
|
|
|
286
470
|
## Technology
|
|
287
471
|
|
|
288
472
|
- [Fabric.js](https://fabricjs.com/) for the 2D editing surface
|
|
289
473
|
- [Three.js](https://threejs.org/) for model loading and real-time 3D rendering
|
|
474
|
+
- [Lucide](https://lucide.dev/) for bundled Workbench controls
|
|
290
475
|
- [Vite](https://vite.dev/) for development and application builds
|
|
291
476
|
- [TypeScript](https://www.typescriptlang.org/) with strict checking enabled
|
|
292
477
|
|
|
@@ -297,3 +482,5 @@ CustomForge is licensed under the Apache License 2.0
|
|
|
297
482
|
See [LICENSE](./LICENSE) for the full license terms
|
|
298
483
|
|
|
299
484
|
Third-party dependencies and assets remain subject to their respective licenses
|
|
485
|
+
|
|
486
|
+
The bundled Nunito Sans font is licensed under the SIL Open Font License 1.1, available in [NunitoSans-OFL.txt](./LICENSES/NunitoSans-OFL.txt)
|