Show your own product photos
To show the design on photos of your own rather than the blank’s, pass them
as mockups. Each is a view of its own, shown in the strip like a blank’s
and switched to with setView(). Pixonaut never learns what they show:
mockups: [ { url: '/img/tee-white.jpg', label: 'White', viewId: 'white', placementRectPx: { x: 115, y: 90, w: 300, h: 380 } }, { url: '/img/tee-green.jpg', label: 'Green', viewId: 'green', placementRectPx: { x: 115, y: 90, w: 300, h: 380 }, shadingStrength: 0.6 },],initialView: 'white',-
localizedLabels(optional,{ fr: 'Blanc' }) is the photo’s label per language, by its code: the strip shows the one in the designer’s language, elselabel. -
viewIdnames the photo’s view forsetView(),initialViewandgetViews(). Left out, the view is named by its place in the list, as a string ('0','1'), which moves when you reorder the list. Your photos have no variants, sosetVariant()rejects with aTypeError. -
The photo is fetched by your customer’s browser, from your own URL. It never reaches the print file, so a wrong or missing photo is a display problem, never a bad print.
-
placementRectPxis measured in that photo, in its own pixels: where the printed area sits on the garment as photographed. Photos from one shoot usually share a rect. -
photoSizePx(optional,{ w, h }) is the size of the photo the rect was measured in, for when your URL serves a smaller copy of it — a downscaled preview of a larger original. The rect is then read in that size and placed on whatever size of image arrives. Leave it out when the rect is in the served image’s own pixels. A zero, negative or infinite edge makes the entry one that cannot be drawn. -
Nothing here is judged against your design. A photo cannot change what gets cut, so there is no rule to refuse one. Labels and order are shown as you give them; only an entry that cannot be drawn at all is skipped.
-
shadingStrength(optional, 0 to 1) sets how strongly the photo’s folds, shadows and highlights show through the design: 0 draws it flat, and leaving it out uses the same default as a mockup photo in the studio. Shading needs the photo’s bytes, so a photo served without CORS headers shows the design flat. A value outside 0 to 1 makes the entry one that cannot be drawn. -
warp(optional) wraps the design round a mug or a bottle in the photo:{ kind: 'cylinder', curvature: 0.8, edgeFalloff: 0.2 }. A curvature of 1 puts the edges ofplacementRectPxon the product’s sides;edgeFalloff(0 to 1, default 0) darkens the print as the surface turns away. The rect stays the print’s size at the front of the product, so a strongly wrapped print looks narrower than it. Leavewarpout, or passnull, for a flat product; a curvature of 0 is refused, and makes the entry one that cannot be drawn, with a line in the console naming it. The wrap needs no photo bytes, so it shows even where shading cannot; the selection handles stay on the flat print. -
displacementStrength(optional, just above 0 to 1) moves the design with the folds and creases of a t-shirt or a bag in the photo, read from the photo’s own light and shade. Leave it out, or passnull, to leave the design where it is. A value outside that range, 0 included, is read as none: the entry is still drawn, unmoved, with a line in the console naming it. Like shading it needs the photo’s bytes, so a photo served without CORS headers shows the design unmoved; the selection handles stay on the unmoved print. -
A photo that will not load leaves the design shown without a backdrop, still printable.
Using a blank’s mockup photos
Section titled “Using a blank’s mockup photos”A mount naming a blank shows its views by itself (see
Views and variants). To pick its photos yourself, the
photos and print areas marked on a blank in the studio can be your
mockups. GET /v1/blanks/{id}/mockups answers each placement’s views, and
each view’s photos with a mount: the photo’s url, its view’s
placementRectPx, its photoSizePx, and its look settings, named as
mockups names them. Pass each one with its view’s label, or a colour name
of your own:
// On your server, with your integration key (ik_…); `apiBase` is the// address of the Pixonaut API, as you pass it to the designer.const res = await fetch(`${apiBase}/v1/blanks/${blankId}/mockups`, { headers: { authorization: `Bearer ${process.env.PIXONAUT_INTEGRATION_KEY}` },});const { placements } = await res.json();const front = placements.find((p) => p.id === 'front');
const flat = front.views.find((v) => v.label === 'Flat');
const mockups = flat.photos .filter((photo) => photo.mount !== null) .map((photo) => ({ label: flat.label, ...photo.mount }));- The
urlopens with no key and is served at the size of the stored preview, which may be smaller than the photo the rect was marked on;photoSizePxsays which size that was, and the designer places the rect on whatever size arrives. - It stays valid for at least 30 days, and at most 60. Any cache, a CDN in front of your store included, may keep the photo that long. Read the blank’s mockups again well inside 30 days, say weekly or whenever your page cache refreshes, and replace the mockups you stored with the new answer. Within one 30-day window every read answers the same url, so a cached copy is reused.
- It stops opening once the photo is replaced on the blank, or the mockup removed; the next read answers the new photo’s url.
mountisnullwhile a photo has not finished uploading: leave that mockup out.- With a publishable key (
pk_…) the same read works from your page in the customer’s browser, which sends its page’s origin. A server-side fetch sends none, so a publishable key is refused there unless you send anoriginheader naming one of the key’s allowed origins.
Omit mockups and the blank’s views are shown, when the mount names a blank;
naming none, no backdrop is drawn.
Questions? Write to [email protected].