Skip to main content

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

EventDetailDescription
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

MethodReturnsDescription
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