I want a storefront for my business that works like Kitchen Universe (https://kitchen-universe.superfast.shop), a demo store built on Crystallize: A kitchen store where the configurator is the shop: start from one of six ready-made kitchens, rearrange it in 3D or let an AI concierge build it from a chat, and watch it priced from its parts in each market — with the yearly catalogue as a PDF made from the live data.
The content model and the wiring below are proven in that store: keep them for the features I want, and rename things to fit my trade. If a feature doesn't fit my business, leave its parts out rather than forcing it. Everything I see is mine to decide: brand, colours, typography, layout, copy and pages. Don't copy the demo's look; build my brand.
What the demo does: product configurator, ai concierge, pdf catalogues, agent checkout, multiple markets, multi-currency. It is B2C, in English, Norwegian, Swedish, Dutch; my markets and languages may differ.
How to work with me
- You need to run commands, edit files and use MCP tools. If you can't (for example in a plain chat), tell me, and suggest I paste this prompt into Claude Code, Cursor or another coding agent instead.
- Ask your questions a few at a time (three to five), in the order of the steps below, and suggest a sensible default for each so I can just say yes. Ask each thing once, even where two lists overlap, and ask the ones that change the build first. Don't start a step before the one before it is done.
- The technical detail below is for you. Talk to me in plain words, and explain a choice only when I need to make it.
- Keep the folder empty until step 5, apart from
.env.local. - Never ask me to paste an access token secret into the chat, and tell me not to paste a filled-in command or its output either. Tell me which command to run or which file to put it in, and I'll do it.
- Before you create or change anything in Crystallize, show me the plan (shapes, pieces, topics, price variants, markets) and wait for my yes. Before an import, show me a sample of five items.
- Use the Crystallize skills (the
skillsMCP tool, or the use-crystallize plugin) for how-to:content-model,information-architecture,taxonomy,data-creation,mass-operations,pricing,query,mutation,js-api-client,responsive-images,payments, and when this store needs themsubscriptions,bookable-resources,vector-rankingandpermissions. Where this prompt and a skill disagree, the skill wins. Check the live schemas with the MCP instead of guessing field names. - When something I asked for isn't possible in Crystallize the way I pictured it, say so and offer the closest thing that is.
- The storefront never reads from the Core API on customer-facing pages. Products, public prices, stock and content come from the Discovery API and the Catalogue API; confidential prices (negotiated B2B price lists) from the Catalogue API on the server.
- Use the Shop API for everything about customers: carts, checkout, customers, orders (including orders created directly, such as renewals), order meta, pipeline stages, payments and subscription contracts. Take the customer identifier from the server session, never from the browser. The Core API is for setup scripts, back-office tools, scheduled jobs and what the Shop API can't do, always on the server and never once per page view.
Step 1: Crystallize tenant, tokens and MCP
Ask me:
- Do I have a Crystallize account and a tenant for this store? If not, I sign up for free at https://app.crystallize.com/signup and create an empty tenant. Ask for its tenant identifier.
- Do I have access tokens? If not, tell me: in the Crystallize App, go to Settings → Access Tokens → Generate a new token, name it, and keep the ID and the secret (the secret is shown once). A token acts with its user's role, so while we build, that user needs to be Tenant Admin (or have a role that can write shapes, pieces, topics, items and prices and run mass operations). Once the store is built, switch the MCP to a token from a read-only user.
- Is the Crystallize MCP connected, with write access? Check that you have its write tools (
run-mass-operation,mutate-core), not only the read tools (tenant-overview,fetch-content-model): with only the read tools, it was added without?exposeWrite=true. If it's missing, have me run this in my terminal with my own token, then restart you:
If the MCP can't be connected in my tool, say so and fall back to scripts that call the Crystallize APIs with the tokens fromnpx add-mcp "https://mcp.crystallize.com/mcp?exposeWrite=true" \ --header "X-Crystallize-Access-Token-Id: <token id>" \ --header "X-Crystallize-Access-Token-Secret: <token secret>".env.local. In Claude Code, also suggest the Crystallize skills:/plugin marketplace add crystallizeapi/ai, then/plugin install use-crystallize@crystallize-ai. The plugin brings its own read-only Crystallize MCP entry with placeholder credentials: keep using the one added above (and add&exposeSkills=falseto its URL once the plugin's skills are installed). - Confirm the connection with
tenant-overview, and tell me what's already in the tenant. If it isn't empty, ask whether to build next to what's there or in a fresh tenant.
The storefront needs the tenant identifier and its own credentials: an access token pair for the Shop API (server only), and a static auth token if Discovery and the Catalogue API are secured. Don't reuse the admin build token in production. Put them in .env.local (have me fill in the secrets) and make sure .env* is in .gitignore.
Step 2: my business and my brand
Ask me:
- What I sell, who buys it, and what makes us different. My brand name and a one-line pitch.
- My markets, currencies and languages, and my VAT/tax setup.
- Where my product data lives today: a spreadsheet or CSV, an export from Shopify, WooCommerce or another platform, a PIM or ERP, my current website, or nothing yet. Where my product images are.
- My brand: logo (SVG if I have it), colours, typefaces, tone of voice, and two or three sites whose look I like. If I have no brand guide, propose a direction from my answers and show it before building pages.
- Where it should run: my own domain, and hosting (suggest Vercel for Next.js).
Then ask what is particular to this kind of store:
- What do I sell: whole kitchens from one maker's range, parts to complete a kitchen, or both? Which ready-made kitchens (layouts like a straight run, an L, an island, a galley, a tall wall) should shoppers start from?
- My range as parts: cabinet types and widths (base, drawer, sink base, corner, wall, tall, oven housing), front ranges and their finishes, worktops, handles, sinks and taps, appliances.
- The rules: what requires what (a sink needs a sink base, an oven needs an oven housing), what excludes what (a handleless front and a knob), and the minimum and maximum of each category in a kitchen.
- How the price is built: per cabinet, fronts and handles counted per cabinet, worktops per centimetre of run, appliances per piece? Are prices stored with or without VAT, and do I want rounded shelf prices per currency?
- Do I have 3D models? In which format, units and origin? If I don't, go through the options below with me and help me pick one:
- Built from dimensions in code, as the demo did: parametric cabinets, fronts and worktops in Python, good for a modular range where every part is a box with doors, drawers and handles.
- The manufacturer's CAD or planner exports (STEP, FBX, OBJ), converted to GLB in Blender, reduced in detail and re-origined to the conventions below.
- A 3D artist, commissioned with the conventions below as the brief.
- Marketplaces (Sketchfab, CGTrader) for props and appliances only: check the licence allows commercial use in a configurator.
- My finishes: the colours with their hex values, and texture scans for wood and stone (or CC0 textures from Poly Haven or ambientCG).
- My markets, currencies, VAT and languages; delivery lead time and installation.
- Do I want a printable quote, a shareable link to a kitchen, and an in-house tool for staff to photograph products and compose the ready-made kitchens?
- Do I make a printed or PDF catalogue today (a yearly catalogue, price lists for dealers)? Which pages, in which languages and currencies?
- Do I want an AI concierge that builds the kitchen from a chat, and which model provider do I have a key for? Should it be open to everyone or limited per visitor?
- Should AI agents (ChatGPT, Gemini and the like) be able to find my kitchens and start a checkout for a shopper?
Step 3: the content model
Create this in my tenant with the MCP, renamed to fit my trade, after I have approved the plan. Keep the structure: it is what the storefront's features depend on.
Build in dependency order, since mass operations run in sequence with no rollback: pieces and shapes (empty first, then their components), topic maps (at most 30 topics per topic/create), price variants, markets and VAT types, the folder tree (two to four levels, five to twelve per level), and only then items. Use lowercase-hyphen identifiers. Decide now which fields are translated and which are discoverable. Restrict every item relation with acceptedShapeIdentifiers. Never add price or stock components to a shape: variants have them built in.
- Pieces:
kitchen-component:materialrelation (up to 10 finishes),requiresandexcludesrelations to the nine part shapes, a specifications table.variant-3d: amodelfiles component acceptingmodel/gltf-binary.dimensions: width, height, depth, length (cm).assembly-delivery: assembly text, lead time in days, installation available, warranty in years, downloads.- Appliance specs, one piece each:
appliance-oven(capacity, cavity width, energy label, pyrolytic, steam),appliance-hob(type, zones, phases, bridge zone),appliance-hood(mounting, extraction, noise, recirculation, duct),appliance-cooling,appliance-dishwasher. seo, and landing blocks:lp-banner,lp-gallery,lp-video,lp-product-slider,lp-story-slider.
- Nine part shapes (products), all with description, short description,
kitchen-component, abrandrelation andassembly-delivery, and the variant componentsvariant-3danddimensions: base-cabinet (unit type: standard, drawer, sink, corner), wall-cabinet, tall-cabinet, front (style: flat, shaker, glass; variants are the finishes), countertop, handle (bar, knob, recessed), appliance (type, available brands, and anappliance-speccomponent choice of the five spec pieces), sink, faucet. - setup (product, a ready-made kitchen): description, USPs, eight repeatable category chunks (base, wall and tall cabinets, fronts, countertops, handles, appliances, sinks and faucets), each with
allowedanddefaultrelations and min and max; astarting-pointchunk, one row per part in run order with the variant named on the relation; aroomchunk (layout straight or L left or right, floor, wall, environment, depth, island and its length and walkway, backsplash);daylight(sun azimuth, elevation, intensity, sky, colour temperature);view(render mode and camera); repeatableopenings(window or door, wall, offset, size, sill, hinge) andlights(ceiling or pendant, position, intensity, colour temperature); seo. Its own variant is priced 0. - material (document): description, a hex
color, finish type (matte, gloss, wood, stone, metal, ceramic), images (the swatch). - brand (document), story (document: intro, hero, paragraphs, featured products and setups, seo), landing-page (document with a multiple-choice of the landing blocks), category (folder).
- Catalogue:
/setups,/products/{base-cabinets,wall-cabinets,tall-cabinets,fronts,worktops,handles,appliances,sinks-and-taps},/materials,/brands,/stories, and/homefor the landing page. - Topic maps: colour (white, cream, beige, grey, green, blue, red, brown, black, wood), style, layout (straight, L-shape, island), collection (the front ranges), media type and source (for images).
- Pricing: gross shelf prices, one price variant per currency:
default(EUR),nok,sek, written from one EUR list price with shelf rounding. Worktops are priced per centimetre. - Markets: international and the Netherlands on EUR at 21 % VAT, Norway on NOK and Sweden on SEK at 25 %. One language per market: en, nl, no, sv.
- Stock: one online warehouse. Order pipelines: Orders (new, processing, shipped, delivered) and Quotes (sent, accepted, lost).
Step 4: my data
Import my products and content with mass operations, mapping my data onto the model: validate each file with build-mass-operation, run it with run-mass-operation and follow it with get-mass-operation-status. Read the operation logs, not just the task status: a task can finish as complete with failed operations, and there is no rollback. Give every upsert a resourceIdentifier so a re-run updates instead of duplicating, and chunk large imports. Start with a small batch, check it in the Crystallize App with me, then run the rest.
Publish every imported item in each language: the storefront only sees published versions (in a mass operation, item/publish needs real itemIds). Import images from URLs with copyRemoteAsset, or upload them (presigned upload, then registerImage). Renditions are generated in a queue: after a large import, republish once they exist, and have the storefront fall back to the original image URL while variants is empty. Before building pages, query Discovery once; if the tenant isn't ignited yet, run igniteDiscoApi (with stacks: opensearch if we use vector ranking), wait for the task to complete, and allow a few minutes. If I have no data yet, create a small, clearly labelled placeholder set (ten or so products) so we can build the pages, and remind me to replace it.
- The demo is one invented maker, Tessel, and one store: 29 products with 53 variants (cabinets, three front ranges in their finishes, four worktops, two handles, five appliances, two sinks and a tap), 28 materials and six setups, in English, Norwegian, Swedish and Dutch. All of it lives as data in the repo and is the single source for the tenant.
- Seed pipeline: a tenant script sets languages, price variants, VAT types, the stock location, pipelines and markets (no mass-operation intent covers them). Everything else is mass operations: pure generators turn the data into numbered operation files (model, taxonomy, catalogue folders, materials, products and relations, setups, translations per language, swatches, stories, landing page), which are committed and replayed in order, stopping at the first failed operation. A check proves the committed files equal the generators' output; a dry run validates without touching the tenant. Translations are updates of the same items by id in each language, with the complete component lists and only the text swapped.
- 3D models: 41 GLBs (1.1 MB together) generated in Python with trimesh by
scripts/generate_glbs.py, uploaded once with their keys cached, then attached to the variants by the operations. - The conventions my models must follow:
- GLB (binary glTF 2.0), in metres, Y up; the wall at z = 0 and the cabinet toward +z.
- The origin at the back-left-bottom corner.
- Named materials swapped at runtime:
FrontandHandletake the chosen finish,Carcassstays neutral. - Named meshes for what moves: doors (with their stack and index, which decides the hinge side), drawers and handles, so doors open in 3D.
- The fixed heights in one table shared by the model generator and the layout (base 87 cm, worktop 4 cm, wall cabinets from 145 cm, tall 215 cm).
- Swatches: one deterministic 512 px image per material from its hex (wood and stone tinted from CC0 Poly Haven textures), uploaded to the material and also used as the front's texture in 3D.
- Imagery: 15 marketing and story images made with Magnific (Seedream), each from a studio render of a setup passed as the reference, reviewed by hand for text, logos and faces, then resized and uploaded once by hash. Every variant and setup also has a studio render, made by the studio tool in a batch.
- HDRIs, floor and wall textures and props are CC0 from Poly Haven.
- From me: my range as parts with their rules and prices, my ready-made kitchens, 3D models (or a plan to get them), finishes with hex values and texture scans, and photos or renders.
Step 5: the storefront
- Next.js (App Router) with react-three-fiber, three.js and zustand. Every page sits under a language prefix, and the language picks the market, the price variant, the currency and the VAT rate; middleware sends a bare URL to the language from a cookie, then
Accept-Language, then English. - Discovery API for the catalogue: one
browseover the nine part shapes andsetupbuilds the configurator's snapshot (products, variants, dimensions, GLB keys, rules, setups), cached per language. The Catalogue API reads stories and the landing page by path, and the draft tree for the App's preview. - The configurator: one store holds the kitchen as an ordered list of cabinets plus one pick per singleton category (front, worktop, handle, sink, tap, appliances). A pure layout function turns that into placed boxes in metres; the 3D scene and an SVG plan both draw from the same boxes, so they never disagree. The plan is also the editor for cabinet order, windows, doors and lights. Requires and excludes come from the catalogue relations, so the rules are data, not code.
- Setups priced from their parts: a setup's own variant is priced 0; its "From" price is the sum of its starting point's parts in the market's price variant. The configurator recomputes the price on every change (fronts and handles per cabinet, worktop per centimetre of run), and the cart is built from the same bill of materials, with a test keeping the two equal.
- Shop API for everything the customer does: carts are hydrated per market (
selectedVariantIdentifier, prices with tax included, the market'staxRate) and carry the market in their meta, so the order keeps its currency; checkout sets the customer, places the cart and creates the order. A shared kitchen is a cart of typewishlistwith the configuration in its meta, which the Shop API keeps without a database of your own. A quote is a printable page of the same bill of materials. - Studio and setup editor (
/studio,/editor): staff tools opened as custom views in the Crystallize App. The studio photographs a variant or a whole setup on a neutral stage (or through an AI pass) and uploads the image onto the variant; the editor composes a setup in the configurator and saves it to the item's draft, then publishes. Only these use the Core API, on the server, behind aSTUDIO_KEYthat the App passes once and the site turns into a cookie; without the key they are closed in production. They are framed only byapp.crystallize.com. - PDFs: the ready-made kitchens as one catalogue (
/<lang>/setups.pdf: cover, contents and a page per kitchen) and each kitchen alone (/<lang>/configure/<kitchen>.pdf, with what can be swapped), rendered on the server with@react-pdf/rendererfrom the same Discovery snapshot and the same bill of materials as the configurator, in the market's currency and the brand's fonts (TTF files bundled with the route). PDFs can't embed WebP, so photos are taken in their original format from the image's own variant ladder. Cached for an hour at the edge. - The concierge: a chat docked in the configurator, on the Vercel AI SDK with Claude. The server route gives the model this kitchen's catalogue (SKUs, prices, sizes, rules) and the kitchen as it stands, sent by the browser with every message; the tools (add, move, swap or remove a cabinet, choose a finish, set the layout, room and island position, add windows and doors, open another kitchen) have no server side: they run in the browser on the configurator's own store, so every change obeys the same rules, shows in 3D at once and can be undone, and each tool answers with the kitchen's new state. Rate-limited per visitor; an optional free-prompt cap is counted in a signed cookie. Env:
ANTHROPIC_API_KEY. - For search engines and AI agents: every page has a Markdown twin (
.md, orAccept: text/markdown),llms.txt, JSON-LD (Product, ProductGroup, Offer, BreadcrumbList), product feeds per market, and agent checkout over the Agentic Commerce Protocol and the Universal Commerce Protocol: an agent's checkout session is a Shop API cart, and the shopper finishes on the store's own checkout page. - Seed scripts use the Core API too: tenant settings (languages, price variants, VAT types, stock location, pipelines, markets) and file uploads.
- Env:
CRYSTALLIZE_TENANT_IDENTIFIER,CRYSTALLIZE_TENANT_ID,CRYSTALLIZE_ACCESS_TOKEN_ID,CRYSTALLIZE_ACCESS_TOKEN_SECRET,STUDIO_KEY, and optionally an image model key for the studio's AI pass.
Build my design, not a demo's: my typefaces, colours and tone, with pages that suit my products. Show me the home page, a category and a product page early, and adjust the design with me before building the rest.
Every page is built for search engines, answer engines and AI agents from the start, not added at the end:
- SEO: server-rendered HTML, one
<h1>, a unique title and description, canonical URLs,hreflangper language, a sitemap androbots.txt, and clean, translated paths. - Structured data: JSON-LD on every page that has a subject:
OrganizationandWebSite(with aSearchAction) on the home page,ProductwithOffer(price, currency, availability) on product pages,BreadcrumbListon categories and products,ArticleorRecipeon content. Generate it from the same data as the page. - GEO, for answer engines and agents:
/llms.txt(an H1, a summary, links to every section),/llms-full.txt, and a Markdown twin of every page (its URL plus.md, orAccept: text/markdown), with prices, stock and facts written out in plain sentences. - Agents can act, not only read: register the store's actions (search, add to cart, check availability) with WebMCP (
navigator.modelContext.registerTool, or annotated forms), and keep the accessibility tree clean: semantic HTML, labelled controls, real buttons and links. - Fast and stable: responsive images from Crystallize, no layout shift (reserve space for images and late content), little client JavaScript. Aim for 100 in every Lighthouse category (Performance, Accessibility, Best Practices, SEO; heavy 3D or video pages may score lower on performance) and pass every Agentic Browsing check.
Step 6: run it, then ship it
Run it locally and walk me through each feature above with my own data. Fix what I find. Before you call it done, run Lighthouse on the home page, a category and a product page (npx lighthouse <url> --only-categories=performance,accessibility,best-practices,seo,agentic-browsing), validate the JSON-LD (https://validator.schema.org), open /llms.txt and a page's .md twin, and fix what falls short. Deploy only when I ask: set the same environment variables on the host, point my domain, and give me the live URL.
Watch out for
- Discovery serves published items only, and a setup's allowed and default relations index against what was published at that moment: publish the parts before the setups.
- Mass operations store every showcase hotspot at 0,0: leave hotspots out of gallery blocks sent that way.
- The Catalogue API doesn't resolve path aliases, and a translated item's path follows its translated name: read structure and paths from English and lay the translated text over it by item id.
- A Shop API hydrate merges identical SKUs into one line, so the run order of the cabinets can't be rebuilt from cart lines: keep the configuration itself in the meta.
- Prices are gross in Crystallize: tell the hydrate so and pass the market's tax rate, or a NOK cart splits its VAT at the wrong rate.
- The model's mesh and material names are a silent contract with the scene: rename one and doors stop opening or fronts stop taking their finish, with no error. Test them.
- The studio waits on animation frames, which a background tab doesn't draw: run its batches in a visible window.
- A replay of the setups overwrites what the editor saved, and an image uploaded after the last cache refresh is overwritten by a replay: refresh the caches from the tenant first.
- Files can't go through mass operations: upload them, then attach the key.
- A PDF renderer needs real TrueType fonts (not WOFF), and a serverless bundle may leave the renderer's own font files behind: require them explicitly and bundle the TTFs with the route.
- The concierge's tools must run on the same store as the panels, never a copy: then it cannot build a kitchen the rules don't allow, and the camera should reframe when a turn has reshaped the room.
- Don't invent facts about my business (prices, stock, certifications, delivery promises). Ask, or leave a clearly marked placeholder.
And for every Crystallize store, from the skills:
- Orders: create and change them through the Shop API
/order(createFromCart,create,setMetawithmerge: true,addToStage,setPayments). Editing an order in Core adds a duplicate to the Shop API's list. Read a customer's orders with the identifier from the session,limit: 100, grouped bycoreId(keep the newest). Seed order history through/ordercreate, not CoreregisterOrder. The order id is the cart id; don't callfulfillaftercreateFromCart. - Payments: create the order from the payment provider's verified webhook, never from the browser, once per cart.
- Cart meta goes in
hydrate(input: { meta });hydrateis the whole cart, so send every line each time. - Images: serve them straight from Crystallize (not through an image optimizer such as
next/imagein its default setup): a WebPsrcsetfrom the returnedvariantswith an accuratesizes, falling back to the original URL while renditions are missing. Replace an image by uploading a new one, not withregisterImageRevision. - Ranking (if the store ranks per shopper): check that
__type(name: "RankByInput")exists; passcontextas a variable, withuserTasteentries of{ vocabulary, weights, magnitude }(magnitude = the square root of the sum of squared weights);tieBreakeris required; don't combinesortingwith ranking, and page withskipandlimitinside the rerank window; introspectTenantRankByFieldfor field names; leavecontextout when there's no taste; useexplain: trueonly for tuning. - Bookings (if the store books): durations are in seconds; the role needs the
bookingPoliciespermission; put the customer on the cart beforebookSkuItem; everyhydratemust resend each booked line with its window and unit, or the booking is cancelled; remove a booking by re-hydrating without it.
Done when
- My tenant has the content model above with my products, prices and images in it.
- The storefront runs on my domain in my brand, and every feature I chose works with my data: we have clicked through each one together.
- Lighthouse scores close to 100 in every category and every Agentic Browsing check passes on the home, category and product pages.
- I know how to add a product, change a price and publish, in the Crystallize App.