Documentation

Build with DesignMint.

Everything you need to put a product configurator on your storefront: install the SDKs, author design rules in the Back Office, and mount the Studio your customers use. This is the usage guide — for a live feel of the end result, open the sandbox.

Start here

Two SDKs, one contract.

DesignMint ships as two React packages that share a single data contract. The Back Office (@intuio/designmint-back-office-sdk) is the merchant workspace where you author design rules — surfaces, print areas, physical sizes, variants, pricing. Saving it produces one serialized metadata string. The Studio (@intuio/designmint-studio) is the customer-facing canvas that consumes that metadata and turns a shopper's design into validated, print-ready output.

Your application sits between them: it persists the metadata after Back Office saves, passes it to the Studio at render time, and stores the customer's canvas data so designs can be restored later.

ProductsBack Officemetadata · base64 json · v3.0StudioPrint-ready output
Setup

Install and get access.

Both packages are published privately under the @intuio scope on npm. You need an access token from the DesignMint team — request one at designmint@intuio.io. Add it to the .npmrc in your project root (keep it out of version control), then install:

.npmrc + terminal
bash
1# .npmrc2@intuio:registry=https://registry.npmjs.org/3//registry.npmjs.org/:_authToken=${INTUIO_NPM_TOKEN}45# install6npm install @intuio/designmint-studio7npm install @intuio/designmint-back-office-sdk
RequirementApplies toNotes
react ≥ 18bothreact-dom ≥ 18 as well.
tailwindcss ≥ 3StudioThe Studio ships no CSS of its own — your Tailwind build generates its classes (setup below).
@medusajs/ui ≥ 2Back OfficePeer dependency of the merchant workspace.
Medusa backendStudioA backend URL + publishable key power uploads, templates, fonts and brand assets.

Tailwind setup. Add the package to your Tailwind content globs so its utility classes are generated, and use the class-based dark-mode strategy — the Studio follows a .dark class on your document root, not the OS preference:

tailwind.config.js
js
1module.exports = {2  darkMode: 'class',3  content: [4    './src/**/*.{js,jsx,ts,tsx}',5    './node_modules/@intuio/designmint-studio/dist/**/*.js',6  ],7}
Studio

Mount it in one component.

The Studio is the default export and needs no providers or wrappers. Give it the metadata your Back Office produced, your priced catalog, and your backend credentials — it handles the rest:

ProductStudio.jsx
tsx
1import DesignMintStudio from "@intuio/designmint-studio"23export function ProductStudio({ metadata, products, customer }) {4  return (5    <div className="h-screen min-h-0">6      <DesignMintStudio7        metadata={metadata}          // Base64 string from the Back Office save()8        products={products}          // your priced catalog (see Product catalog)9        productCanvasData={{}}       // or a previously saved canvas-data map10        backendUrl={BACKEND_URL}11        publishableKey={PUBLISHABLE_API_KEY}12        customerId={customer?.id ?? null}13        currencyCode="usd"14        onAddToCart={async (items) => { /* create the cart lines */ }}15      />16    </div>17  )18}
The Studio fills its parent. Give the wrapper a real height and min-height: 0 on flex parents — without it the canvas cannot lay itself out. In a modal, something like h-[calc(100vh-200px)] works well.
Browser-only. The Studio renders with canvas and requestAnimationFrame. In SSR frameworks load it client-side only — in Next.js: dynamic(() => import('@intuio/designmint-studio'), { ssr: false }) inside a client component.
Studio

Props reference.

Required props first. Money and currency codes are always lowercase (e.g. "usd").

PropTypeWhat it does
metadatastring · reqThe Base64 metadata from the Back Office. Decoded internally — never parse or edit it yourself.
backendUrlstring · reqAPI base URL used for uploads, templates and brand assets.
publishableKeystring · reqMedusa publishable key sent with backend requests.
customerIdstring|null · reqThe signed-in customer, or null for guests and admin use.
currencyCodestring · reqCurrency for all pricing, e.g. "usd". Case-insensitive.
productsPricedProduct[]Your catalog. Optional in types, required in practice for pricing and ordering.
productCanvasDataobjectA previously saved canvas-data map. Pass it back to restore designs exactly; {} starts fresh.
studioRefref objectImperative handle passed as a PROP (not ref=). Exposes save(), legacySave() and loading.
isAdminbooleantrue mounts the full editor with pricing tools; false (default) is the customer PDP mode.
productThumbnailsobjectPer-product thumbnail selection ({ variantIds, designId }).
colorstringTailwind accent color name for buttons and highlights. Default "blue".
brandIdstringEnables brand-asset management behaviors.
onAddToCartasync fnCalled with one item per order line after files are exported and uploaded.
onUploadedFilesChangefnNotifies you as the customer’s uploaded files change.
Data

The product catalog contract.

products carries your priced catalog. Three rules matter most: every product.id must match a productId inside the metadata; money is always a per-currency record like { usd: 45 }; and color swatches appear only when every variant declares attributes.colorCode.

product.ts
ts
1{2  id: "prod_…",                     // must match a productId in the metadata3  title: "Windbreaker Jacket",4  basePrice: { usd: 45 },5  variants: [{6    id: "variant_…",7    title: "Red / S",8    attributes: { color: "Red", colorCode: "#DC2626", size: "S" },9    price: { usd: 40 },10    inventoryQuantity: 3,           // enables the stock guard at ordering11  }],1213  // Quantity pricing — provide ONE of the two:14  quantityTiers:   [{ minQty: 12, pricePerUnit: { usd: 40 } }],   // stepper15  fixedQuantities: [{ quantity: 500, totalPrice: { usd: 17500 } }], // dropdown1617  availablePrintingTechniques: [{18    id: "sublimation", label: "Sublimation",19    perDesignPrice: { usd: 12 }, designNames: ["Design 1", "Back"],20  }],21}

Unit prices resolve in a fixed order: fixed-quantity match → quantity tier → variant price → product basePrice. A tier without maxQty means "and up".

Admin-only fields. podCharge and sizeCharges feed the admin pricing panels only — they are never added to storefront line prices.
Studio

Saving, exports and add to cart.

Persistence is imperative. Pass a studioRef and call its methods when you want output — the Studio never saves anything on its own:

save.ts
ts
1const studioRef = useRef(null)23// Full export — file CONTENT (data URLs / bytes), not hosted URLs:4const { exports, productCanvasData } = await studioRef.current.save()56// Per-variant white-background mockup JPEGs:7const { variants } = await studioRef.current.legacySave()

Persist productCanvasData and pass it back on the next mount to restore the canvas exactly, decorations included. To upload the returned file content, use the bundled helpers — uploadStudioExports, uploadStudioMockups and saveBrandAssetsToDb. The upload helpers run all uploads in parallel and reject the whole call if any single upload fails, so wrap them in try/catch. Their optional authToken falls back to the stored Medusa admin token.

When a customer confirms an order, the Studio exports and uploads the files, then calls onAddToCart with one item per line: { variantId, quantity, metadata: { decorationId, files, thumbnail, personalization } }.

Mockup caveat. save() renders mockups with the first variant's photos. If you need per-variant imagery, use legacySave() or the proof download.
Back Office

The merchant workspace.

The Back Office takes exactly five props and talks to no backend of its own — saving is host-driven through an imperative handle, and the SDK never persists anything itself:

BackOffice.jsx
tsx
1import { useRef } from "react"2import { DesignMintBackOffice } from "@intuio/designmint-back-office-sdk"34const backOfficeRef = useRef(null)56<div className="flex h-full min-h-0">7  <DesignMintBackOffice8    actor="admin"                 // admin | vendor | microstore9    backOfficeRef={backOfficeRef}10    metadata={savedMetadata}      // "" for a fresh session11    products={products}12    editableVariants={true}13  />14</div>1516// Save — validate, then persist the returned string:17const result = await backOfficeRef.current?.save()18if (result?.success) await api.saveMetadata(result.metadata)19else showErrors(result.errors)   // [{ message }]
PropTypeWhat it does
backOfficeRefref object · reqImperative handle; save() validates and serializes all products into one metadata string.
metadatastring · reqA previously saved metadata string, or "" to start fresh. Entries for products missing from the catalog are filtered out on load.
productsProduct[] · reqThe catalog to author rules for (same shapes as the Studio catalog, plus printLocations and lock).
actorenum · req"admin", "vendor" or "microstore" — selects the upload endpoint and permissions for image uploads.
editableVariantsbooleanWhen true, the Products panel lets the merchant include or exclude individual variants.

Validation gates saving: every design area must resolve to a print size and every required component must be linked, or save() returns success: false with a clear error list and the canvas marks the offending areas. For product cloning, the SDK exports remapMetadataIds and remapCanvasDataIds to rewrite database ids inside saved payloads, and MetadataUtils if you need to inspect metadata server-side.

Back Office

Authoring a product, step by step.

01

Start a document

File → New opens an Illustrator-style dialog: pick a real print format from the paper catalog (A-series, letter, posters, cards, brochures…) or set custom width, height and orientation; choose how many design surfaces you need, the export DPI (150 / 300 / 600), CMYK or RGB, per-side safe margins, and at least one output format (SVG, PDF, PNG).

02

Add design surfaces

Use the Assets panel to upload product photos (JPG, PNG, WebP up to 10 MB) or paste an image URL. Clicking an image applies it to the active design view and variant. Calibrated paper sheets from step 1 need no upload — they are generated locally.

03

Draw the print areas

Press D and drag on the canvas. Areas snap to edges, centers and guides (hold Alt to disable). Move, resize with the eight handles, restack from the Layers panel, and use the right-click menu for copy, paste, duplicate, align and fit/fill.

04

Set true-to-size printing

On a calibrated sheet the scale is fixed by the paper size. On a photo mockup, type an area's real print size (in / cm / mm) once to declare the scale — one scale per design keeps everything consistent, and the panel shows the resulting pixel output and DPI live.

05

Cover the variants

The right rail switches products and variants; variants with color codes group into swatches so you author once per color. Fill per-variant images by upload, URL, recolor (perceptual tint with intensity and brightness), a bulk ZIP upload, or Replicate — which copies areas and images across products and variants, matched by name or position.

06

Configure the customer experience

The gear opens design configuration: sell the product with the full Studio, a simple form, or as-is. In Studio mode, seven toggles decide what customers may use — text, icons, uploads, colors, layers, embroidery, templates. Reusable input components (text, image, email, number, URL, embroidery) attach to specific areas from the Components tab.

07

Price it

Set base price, per-size surcharges and technique pricing (flat per-design, or stitch-count tiers for embroidery). The price bar shows base · decoration · total as you work, with a full per-size breakdown one click away.

08

Save

Hit ⌘ S or your Save button — the host calls save(), validation runs, and on success you receive the metadata string to persist. Amber markers point at anything that blocks saving.

Shortcuts worth learning: D design tool · P pan · Tab cycle areas · ⌘ Z/⌘ ⇧ Z undo/redo · ⌘ scroll zoom at cursor · Esc deselect.

Studio

What your customers get to do.

Mounted without isAdmin, the Studio opens in the ordering view with an Edit Design expander. Customers work with exactly the tools you enabled per product: template library, styled text (with curves and effects), icons and shapes, their own uploads (JPG, PNG, GIF, SVG, DST stitch files, even custom fonts), fills and per-element color control, layers, and embroidery with live stitch counts.

The canvas keeps them honest without blocking them: live print-size badges, safety and bleed pills, and per-element warnings when artwork resolution drops below the target DPI or drifts outside the printable area. Switching a color variant swaps the product photo — never their artwork. Up to 20 saved design variations per product let them explore before committing.

Ordering is a line-item table: option dropdowns and color swatches per row, quantity as a dropdown (fixed lots) or a tier-snapping stepper, a per-row Personalize drawer for the input components you defined, and a stock guard that blocks over-stock rows. Add To Cart exports the print files, uploads them, and hands your onAddToCart callback one clean item per line.

Data

Metadata is the contract.

Everything the two SDKs agree on travels in one Base64-encoded JSON string, currently format v3.0. The Back Office produces it, your application stores it, the Studio consumes it. Treat it as opaque: never parse or hand-edit it — both SDKs decode it internally, and MetadataUtils exists for the rare server-side inspection.

Round-trips are guaranteed: feeding a saved string back restores identical state. Products or variants that no longer exist in your catalog are silently filtered out on load. When you clone a product, rewrite the ids inside both payloads with remapMetadataIds / remapCanvasDataIds instead of regenerating the design work.

Support

When something looks off.

SymptomWhereFix
Canvas never lays outbothThe wrapper has no real height. Give it one, and min-height: 0 on flex parents.
npm install → 404setupThe @intuio scope is private — your .npmrc token is missing, expired, or lacks scope access.
Unstyled / broken UIStudioYour Tailwind content globs don’t include the package dist, so its classes were never generated.
Mixed dark & light UIStudioUse darkMode: "class" in Tailwind. The Studio follows a .dark class on <html>, not the OS theme.
Save blockedBack OfficeValidation failed — check result.errors; amber markers show the areas missing a print size or component link.
Uploads all failedhelpersUpload helpers reject the whole batch if one file fails — wrap calls in try/catch and retry.
Low-res warnings varyStudioThresholds scale with each product’s export DPI — the same image can pass at 150 and flag at 600.
Designs disappear on reloadBack Officesave() prunes deselected designs. Never feed pruned output back as input for master-design flows — merge with the master’s full design list.

Still stuck? Write to designmint@intuio.io — the engineers who built DesignMint are the ones on the pager.