Add product
Six short steps. Everything goes to Shopify as a draft — nothing is live until you press Publish.
Start from a similar product saves the most time
Copies its attributes, features, notes and sizes. You still add your own colours and photos.
Basics
SKUs are made for you: LAM-LTHR01-8X4-OLVGRN-MAT
Look
Finish
Material
Features tap to add · up to 4
Where to use
More fields — series, surface, slip rating, sample price, stock…
Type ₹ / sq ft or the price per pack — the other fills itself. The site shows ₹/sq ft; the cart charges per pack.
| Size * | ₹ / sq ft | Price ₹ per pack * | MRP ₹ per pack | Pieces / pack | Coverage / pack (sq ft) auto from size |
|---|
Each colour's photos show only when that colour is picked on the site. Its first photo is the main image. Leave the name blank for a single-colour product.
Colour family ticked for you from the colour names
Images made from each colour's main photo
Made as soon as you add photos — the main photo should be a flat, straight-on swatch.
Description
SEO audit
Every product scored against the rubric. Click a row to load its copy in SEO copy.
SEO copy
Meta title, description and keywords are a template over stored metafields — no model call, free and repeatable. The model only writes long-form body copy, and only if a key is set.
Images
Gemini Vision reads your supplier photos, then generates one render per scene and attaches them to the product. Scenes are per category.
Read in the browser and sent as base64. Two or three angles beats one.
Flat templates
Every image that can be built from one flat swatch — no model call, no cost, a few hundred milliseconds. Fixed geometry over your own photo: the size shot, the thickness shot, the laid-floor grid, the pattern repeat.
Parsed by the same parseSizeLabel the product form uses — mm, cm, inch or ft.
Laminates & panels get feet on the size drawing; the rest mm.
Glazed tiles get a pale body edge; full-body carries the face colour through.
Capped by the photo: a 640px swatch cannot fill 2048.
Wants a flat, square-on shot of the surface — the kind of photo a supplier sends. An angled studio render will look skewed when pasted into fixed geometry, which is itself worth seeing once.
Icon is picked from the words: UV/sun, water, fire, light weight, durable, scratch/stain, termite, vertical/install, flexible — anything else gets a check mark.
Studio shot — 3D render
The same swatch, but built as an actual scene: a slab with real thickness on a floor, two rectangular lights, a camera with a focal length. Roughness is a property of the material here, so a matte and a polished tile genuinely differ — the one thing the 2D composite cannot express. Seconds rather than milliseconds, still no model call.
CHROME_PATH if it is somewhere unusual.
The only thing that varies per product — it decides whether the surface scatters light or mirrors it. Everything else (size, thickness, body and ground colour) is read from the fields above.
Rectify a photo
Every template assumes a flat, square-on swatch. Hand one an angled photo and it produces confident nonsense — the beige backdrop of a studio shot gets pasted in and called a tile. This finds the tile's four corners and undoes the camera's perspective, so a phone photo becomes a usable swatch.
python3 -m venv .venv-cv && ./.venv-cv/bin/pip install opencv-python-headless numpy.
A tile on a plainish background. The corners are found by colour, so texture is fine.
Sets the output aspect, so a plank straightens to 2:1 rather than to whatever the camera saw.
PDF images
Pulls every picture embedded in a catalogue PDF at its original resolution — not a screenshot. Works whatever the layout, because a PDF stores each image once as its own object. Transparent cutouts come out as PNG with their transparency; repeats are kept once. Flat-colour swatches drawn as vector shapes are rendered at 300 dpi with their colour code. Backgrounds reused across pages count as decoration: hidden, and left out of the zip.
Room renders · the Cycles PDP pack
A real path-traced render, not a composite. The tile is built as actual geometry at its real size — a 1200 x 600 slab is 1.2 x 0.6 m with a 3 mm joint and a 1.5 mm chamfer — and Cycles works out the light. Three catalog-ready shots per SKU.
This is minutes, not milliseconds, and it needs Blender on the box. Nothing here calls a model, so the cost is electricity.
1 · the room
Every .blend in lib/productImages/templates/. Drop one in
and press Refresh — nothing to restart. The grey box is a calibration room for
checking tile scale and grout, not a product shot.
Multiplies the scene's own lamps and emissive surfaces. A bought interior is lit for mood, and the floor is the product — 2 to 3 opens it up. Unlike exposure this adds real light, so the tile's pattern keeps its contrast.
The artist framed their kitchen; that is usually right. But a low camera views the floor at a grazing angle and flattens a patterned tile to nothing — pick auto for those.
Leave blank. Tone mapping only, so it lifts the black point too and flattens texture — measured, +1.6 EV cost 18% of the tile's pattern contrast. Use Lighting first.
2 · the tile
Parsed for real millimetres. This is what sets the tile's size in the room.
Sets roughness and the clear coat. It is what the grazing shot exists to prove.
3 · how it is laid
Herringbone is not in this build: it interlocks only at 2:1 and needs its own lattice.
2048 is a PDP zoom. Drop to 768 while you are tuning — it is roughly 7x faster.
Signals
GA4 funnel data → a relevance score and the Popular / Trending / Bestseller tags. Preview computes everything and writes nothing.
GCP_PROJECT_ID and GA4_DATASET, and a GA4→BigQuery export
behind them. Without both it refuses rather than querying a guessed dataset.
Marketing
Journeys are data, not code. A channel with no key reports itself off rather than pretending.
Ads events
Builds the Meta Conversions API payload so you can check the hashing without firing anything. Email and phone are SHA-256 hashed before they leave this process.
Settings
Some routes need the x-cron-secret header. It's kept in this browser's
localStorage only — never sent anywhere but this service.
Find it with grep CRON_SECRET material-admin/.env
Routes
Everything this service exposes.