Quick Start
Get a product customizer running in under 5 minutes.
Basic Setup
1. HTML (plain script)
Add a container div, then call createCustomizer. It registers web components automatically, creates <cv-customizer>, and appends it to the container — no extra setup needed.
<!DOCTYPE html>
<html>
<head>
<title>My Product Customizer</title>
</head>
<body>
<div id="customizer"></div>
<script type="module">
import { createCustomizer } from '@chamevo/customizer';
const customizer = createCustomizer('#customizer', {
stageWidth: 900,
stageHeight: 600,
});
customizer.addEventListener('cvReady', async (e) => {
const { chamevo, canvas } = e.detail;
await customizer.loadProduct({
title: 'T-Shirt',
views: [
{
title: 'Front',
thumbnail: '/images/tshirt-front-thumb.jpg',
elements: [
{
type: 'image',
source: '/images/tshirt-front.png',
title: 'T-Shirt Front',
parameters: {
left: 400,
top: 300,
draggable: false,
removable: false,
},
},
],
options: {
stageWidth: 900,
stageHeight: 600,
},
},
],
});
});
</script>
</body>
</html>
2. With Build Tools (TypeScript)
// main.ts
import { createCustomizer } from '@chamevo/customizer';
const customizer = createCustomizer('#customizer', {
stageWidth: 900,
stageHeight: 600,
});
customizer.addEventListener('cvReady', async (e: CustomEvent) => {
const { chamevo, canvas } = e.detail;
// Programmatically add elements via the canvas
await canvas.addElement('text', 'Hello World', 'My Text', {
fontSize: 32,
fill: '#333333',
left: 400,
top: 300,
draggable: true,
resizable: true,
});
});
Framework Integration
React
import { useEffect, useRef } from 'react';
import { defineCustomElements } from '@chamevo/customizer';
import type { CVProduct } from '@chamevo/types';
defineCustomElements();
interface CustomizerProps {
product: CVProduct;
onReady?: (detail: { chamevo: any; canvas: any }) => void;
}
export function ProductCustomizer({ product, onReady }: CustomizerProps) {
const customizerRef = useRef<HTMLCvCustomizerElement>(null);
useEffect(() => {
const el = customizerRef.current;
if (!el) return;
el.loadProduct(product);
const handleReady = (e: CustomEvent) => onReady?.(e.detail);
el.addEventListener('cvReady', handleReady);
return () => el.removeEventListener('cvReady', handleReady);
}, [product, onReady]);
return (
<cv-customizer
ref={customizerRef}
options={JSON.stringify({ stageWidth: 900, stageHeight: 600 })}
/>
);
}
Vue
<template>
<cv-customizer
ref="customizer"
:options="JSON.stringify({ stageWidth: 900, stageHeight: 600 })"
@cvReady="onReady"
/>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { defineCustomElements } from '@chamevo/customizer';
import type { CVProduct } from '@chamevo/types';
defineCustomElements();
const props = defineProps<{
product: CVProduct;
}>();
const customizer = ref<HTMLCvCustomizerElement>();
onMounted(() => {
if (customizer.value) {
customizer.value.loadProduct(props.product);
}
});
const onReady = (e: CustomEvent) => {
const { chamevo, canvas } = e.detail;
console.log('Customizer ready:', chamevo);
};
</script>
Headless Mode (Core Only)
For complete control over the UI, use the core package directly:
import { ChamevoJS, ChamevoCanvas } from '@chamevo/core';
// Create a canvas element in your HTML
const canvasEl = document.getElementById('my-canvas') as HTMLCanvasElement;
// Create ChamevoCanvas (FabricJS wrapper)
const canvas = new ChamevoCanvas(canvasEl, {
width: 900,
height: 600,
backgroundColor: '#ffffff',
});
// Create ChamevoJS orchestrator
const chamevo = new ChamevoJS({
canvas,
options: {
stageWidth: 900,
stageHeight: 600,
},
});
// Listen to events
chamevo.on('productCreate', ({ product }) => {
console.log('Product loaded:', product);
});
chamevo.on('elementSelect', ({ element }) => {
console.log('Selected:', element);
// Update your custom UI
});
// Load a product
await chamevo.loadProduct({
title: 'T-Shirt',
views: [
{
title: 'Front',
elements: [
{
type: 'image',
source: '/images/tshirt.png',
title: 'T-Shirt',
parameters: { left: 450, top: 300, draggable: false },
},
],
},
],
});
// Add elements programmatically
await canvas.addElement('text', 'Custom Text', 'My Text', {
fontSize: 24,
fill: '#000000',
draggable: true,
resizable: true,
});
// Get product data for saving
const productData = chamevo.getProduct();
Key Concepts
cv-customizer Events
| Event | Detail | Description |
|---|---|---|
cvReady | { chamevo: ChamevoJS, canvas: ChamevoCanvas } | Customizer initialized |
cvProductCreate | { product: CVProduct } | Product loaded |
cvViewSelect | { view: CVView, index: number } | Active view changed |
cvElementSelect | { element: unknown } | Element selected/deselected |
cvPriceChange | { price: number, singleProductPrice: number } | Price updated |
cv-customizer Methods
| Method | Returns | Description |
|---|---|---|
loadProduct(product) | Promise<void> | Load a product |
selectView(index) | Promise<void> | Switch active view |
getProduct() | Promise<CVProduct> | Get serialized product |
getOrder() | Promise<unknown> | Get full order data |
getElements(viewIndex?, type?) | Promise<unknown[]> | Get serialized elements |
undo() | Promise<void> | Undo last action |
redo() | Promise<void> | Redo last undone action |
reset() | Promise<void> | Clear all views |
Next Steps
- Configuration Options - Customize everything
- Components - Web component reference
- Architecture Overview - Understand how it works