SudoMock
Mockups
DocsPricing
Request a demo
Get Started

Start rendering mockups in minutes

From PSD to product mockup in one API call.

Get Free API Key→Browse Templates
Public status pagePublished API pricingProduct mockup API500 one-time API credits

Site Navigation

SudoMock

Turn reusable PSD templates, artwork, and editable text into production-ready product images through REST API, no-code workflows, native storefront apps, or AI.

SudoMock is a registered DBA
1209 Mountain Rd Pl NE, Ste N
Albuquerque, NM 87110, USA

Product

  • Pricing
  • Dashboard
  • PSD Mockups
  • Changelog
  • Start Free

Developers

  • API Overview
  • MCP Server
  • Quick Start
  • Render API
  • Upload PSD
  • Authentication
  • Error Handling
  • PSD Preparation
  • Integrations

Mockups & Tools

  • All Mockups
  • Apparel Mockups
  • Drinkware Mockups
  • Wall Art Mockups
  • Home & Living
  • By Platform
  • Search Mockups
  • Background Remover
  • Free Tools

Resources

  • All Use Cases
  • T-Shirt Mockup Generator for Print on Demand
  • Tote Bag Mockup Generator for Sustainable Brands
  • Automate Mug at Scale with SudoMock
  • Blog
  • Roadmap
  • All Alternatives
  • vs Placeit
  • vs DynamicMockups
  • vs Adobe Photoshop API
  • vs Static Mockup Generators
  • vs AI Image Editors

Company

  • About
  • Contact
  • Brand Assets
  • System Status (opens in new tab)
  • Feature Requests (opens in new tab)
Blog

Latest Articles

View all →
  • 01Seamless Repeat Pattern Check: Find and Fix a Seam Before It Prints
  • 02Batch Replace Smart Objects in Photoshop: Script or API
  • 03WooCommerce Product Placeholder Image: Change It, Then Replace It
  • 04Amazon Product Image Requirements: The Rules and Where a Mockup Fits

© 2026 SudoMock. All rights reserved.

PrivacyTermsRefundsCookies[email protected]
  1. Blog
  2. /
  3. Tutorial

Seamless Repeat Pattern Check: Find and Fix a Seam Before It Prints

A repeat pattern is seamless when everything leaving one edge of the tile comes back in at the opposite edge. Check every tile before it goes on a product: SudoMock's seam check is free, answers in the same call with seamless, faint_seam or visible_seam and the join that breaks, and a fix returns a repaired tile.

Published Nov 5, 2026·7 min read·Beck

A pattern tile repeated twice each way with its left_right and top_bottom joins marked, beside two tee renders of the same pattern, one with visible join lines and one without

Key takeaways

  • A seam that is invisible in one tile shows at every join once the tile repeats on a product.
  • Send crop_aspect when the render crops the tile, so the check sees the same cut.
  • Gate every render on the check: render seamless tiles, fix visible seams, return the rest.

On this page

  • What makes a repeat pattern seamless
  • One seam becomes a grid on the product
  • Check a tile by eye in Photoshop
  • Check every tile by API before it is rendered
  • Fix a seam without redrawing the tile
  • Gate a whole collection on the check
  • Let an agent check before it renders
  • Next step
  • Frequently asked questions
  • Sources

What makes a repeat pattern seamless

The right edge of a tile has to run on into its left edge, and the bottom into its top, so each copy meets the next with nothing to mark the join. Two faults cause most seams: a motif cut at one edge that never reappears on the other side, and a background whose tone or texture changes from one side of the tile to the other.

The same orange and leaf motifs in two tile files, each repeated three by three: on the left, cut motifs and a darker corner mark a grid of joins; on the right, the repeat runs on with no visible joinTwo tile files drawn for this post with the same motifs, each repeated three by three. Left: motifs drawn once and a background that darkens toward one corner. Right: every motif that crosses an edge is drawn again on the opposite side.

Seen on its own, each of these tiles looks finished. The left one only breaks where its copies meet, so a preview of the single file gives nothing away.

One seam becomes a grid on the product

A product render repeats exactly what is in the file, so a join that breaks once in the tile breaks at every repeat. On the tee below, one tile's breaks become a grid of squares across the whole print.

Two renders of a white tee with a printed orange pattern panel: on the left, faint vertical and horizontal lines divide the print into squares; on the right, the pattern runs on without linesBoth tiles on the same tee PSD, 1,600 pixels per tile in the print area, tile set to true. SudoMock renders, 5 November 2026.

The two renders differ only in the tile URL. Each is the ordinary tiled request from Pattern mockups by API: "tile": true and the size of one tile in the smart object's asset, here on a white tee like the ones in the t-shirt mockup templates. A buyer who zooms into the left listing photo sees the squares at once, and a printed run carries the same lines.

Check a tile by eye in Photoshop

The manual check moves the joins into the middle of the canvas, where they are easy to see. In Photoshop, choose Filter > Other > Offset and pick Wrap Around for the undefined area, as Adobe's Julieanne Kost shows in How to Create a Seamless Pattern (Tile) in Photoshop (21 January 2015). Shift the tile by about half its width and half its height: the four edges now meet in a cross through the center, and a cut motif or a step in tone shows along it.

This works for one file you have open. It does not scale to a collection of a few hundred tiles in several colorways, and it checks the whole file even when the product crops the tile to another shape.

Check every tile by API before it is rendered

The SudoMock seam check takes a PNG, JPEG or WebP tile as a public URL or as base64 and answers in the same call. A check is free, and the same image checked again answers at once.

curl -X POST https://api.sudomock.com/api/v1/check-seams \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/orange-grove-tile.png",
"crop_aspect": 1.5
}'
const response = await fetch('https://api.sudomock.com/api/v1/check-seams', {
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"url": "https://example.com/orange-grove-tile.png",
"crop_aspect": 1.5
}),
});
const data = await response.json();
console.log(data);
import requests
response = requests.post(
"https://api.sudomock.com/api/v1/check-seams",
headers={
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
json={
"url": "https://example.com/orange-grove-tile.png",
"crop_aspect": 1.5,
},
)
print(response.json())
package main
import (
"bytes"
"fmt"
"io"
"net/http"
)
func main() {
payload := []byte(`{
"url": "https://example.com/orange-grove-tile.png",
"crop_aspect": 1.5
}`)
req, err := http.NewRequest("POST", "https://api.sudomock.com/api/v1/check-seams", bytes.NewBuffer(payload))
if err != nil {
panic(err)
}
req.Header.Set("x-api-key", "YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
<?php
$payload = <<<'JSON'
{
"url": "https://example.com/orange-grove-tile.png",
"crop_aspect": 1.5
}
JSON;
$ch = curl_init('https://api.sudomock.com/api/v1/check-seams');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'x-api-key: YOUR_API_KEY',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => $payload,
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;

crop_aspect is for a render that places the tile with fit set to crop: send the width of the tile size in the render divided by its height (1 for a square tile), and the check cuts the image exactly the way the render will, then checks that cut. Leave it out to check the whole image, which is what a render with fill repeats.

The answer to act on is data.status:

statusWhat it meansWhat to do
seamlessThe copies meet with no line.Render.
faint_seamA slight line that can show on close inspection.Render, or fix it for a print seen up close.
visible_seamA line most people will notice.Fix it, or ask the designer for a new file.

data.seams lists only the joins that break. left_right is where the right edge of one copy meets the left edge of the next, and top_bottom is where the bottom edge meets the top. Each entry carries ranges, half-open pixel spans along that join, rows on left_right and columns on top_bottom, so a review screen can point at the exact stretch. The check seams reference shows this answer for a 2,048 pixel tile that breaks along its left and right edges:

JSON
{
"data": {
"status": "visible_seam",
"seams": [
{
"side": "left_right",
"status": "visible_seam",
"ranges": [[0, 412], [1630, 2048]]
}
],
"width": 2048,
"height": 2048,
"fixable": true,
"unfixable_reason": null,
"previous_fix": null
},
"success": true
}

Fix a seam without redrawing the tile

A tile with a seam can be repaired as a job, and the check already says whether the fix will take it. fixable is false when the tile has transparent pixels along its edges (unfixable_reason reads transparent_edges; fill the edges in the design file first) or is larger than a fix takes (too_large), and the fix refuses both before anything is charged.

Send the same body to the fix endpoint with an Idempotency-Key, so a retry returns the same job instead of starting a second fix:

curl -X POST https://api.sudomock.com/api/v1/fix-seams \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: orange-grove-tile-v1" \
-d '{
"url": "https://example.com/orange-grove-tile.png",
"crop_aspect": 1.5
}'
const response = await fetch('https://api.sudomock.com/api/v1/fix-seams', {
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
'Idempotency-Key': 'orange-grove-tile-v1',
},
body: JSON.stringify({
"url": "https://example.com/orange-grove-tile.png",
"crop_aspect": 1.5
}),
});
const data = await response.json();
console.log(data);
import requests
response = requests.post(
"https://api.sudomock.com/api/v1/fix-seams",
headers={
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json",
"Idempotency-Key": "orange-grove-tile-v1",
},
json={
"url": "https://example.com/orange-grove-tile.png",
"crop_aspect": 1.5,
},
)
print(response.json())
package main
import (
"bytes"
"fmt"
"io"
"net/http"
)
func main() {
payload := []byte(`{
"url": "https://example.com/orange-grove-tile.png",
"crop_aspect": 1.5
}`)
req, err := http.NewRequest("POST", "https://api.sudomock.com/api/v1/fix-seams", bytes.NewBuffer(payload))
if err != nil {
panic(err)
}
req.Header.Set("x-api-key", "YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", "orange-grove-tile-v1")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
<?php
$payload = <<<'JSON'
{
"url": "https://example.com/orange-grove-tile.png",
"crop_aspect": 1.5
}
JSON;
$ch = curl_init('https://api.sudomock.com/api/v1/fix-seams');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'x-api-key: YOUR_API_KEY',
'Content-Type: application/json',
'Idempotency-Key: orange-grove-tile-v1',
],
CURLOPT_POSTFIELDS => $payload,
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;

The call answers 202 with a job_id. Poll the job until status reads succeeded, failed or cancelled, or subscribe an endpoint to the seam_fix.succeeded and seam_fix.failed webhooks. A finished fix carries result_url, the repaired tile at the same width and height; result_status, a fresh check of that tile; and changes, which reads edges when only the area along the joins changed and whole_tile when the tile was rebuilt. When alternative_url is set, a second repair passed too, so show both to whoever approves the collection.

A failed fix is refunded. A later check of the same image with the same crop_aspect hands back your latest successful repair in previous_fix, so you can reuse that repair instead of paying for a second fix. Render with result_url as the artwork, with the same fit and tile size you checked with.

Gate a whole collection on the check

For a collection, put the check in front of every render: seamless and faint tiles go straight to the render, tiles with a visible seam go to the fix, and the ones the fix cannot take go back to the designer with the join and the ranges. Because the check is free, it costs nothing to run it on every tile, the ones you believe are clean included.

JavaScript
import { randomUUID } from "node:crypto";
const API = "https://api.sudomock.com/api/v1";
const KEY = { "x-api-key": process.env.SUDOMOCK_API_KEY };
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function post(path, body, extra = {}) {
for (;;) {
const res = await fetch(`${API}/${path}`, {
method: "POST",
headers: { ...KEY, "Content-Type": "application/json", ...extra },
body: JSON.stringify(body),
});
if (res.status === 429) {
await sleep(1000 * Number(res.headers.get("Retry-After") || 5));
continue;
}
if (!res.ok) throw new Error(`${path} answered ${res.status}`);
return res.json();
}
}
// Returns the tile URL to render, or tile: null with a note for the designer.
async function readyTile(url, cropAspect) {
const body = cropAspect ? { url, crop_aspect: cropAspect } : { url };
const { data } = await post("check-seams", body);
if (data.status !== "visible_seam") return { tile: url, note: data.status };
if (data.previous_fix) return { tile: data.previous_fix.result_url, note: "fixed before" };
if (!data.fixable) return { tile: null, note: data.unfixable_reason, seams: data.seams };
let job = await post("fix-seams", body, { "Idempotency-Key": randomUUID() });
const id = job.job_id;
while (!["succeeded", "failed", "cancelled"].includes(job.status)) {
await sleep(3000);
const r = await fetch(`${API}/jobs/${id}`, { headers: KEY });
if (r.ok) job = await r.json();
}
if (job.status !== "succeeded") return { tile: null, note: job.error?.error_code ?? job.status };
return { tile: job.result_url, note: `fixed: ${job.changes}` };
}

Pass each returned tile into the render request of every product that uses the same fit and tile shape; a product that crops the tile to another shape gets its own readyTile call with its own crop_aspect. A render that repeats a tile whose check found a visible seam adds TILE_SEAM_VISIBLE to its warnings and still succeeds, so a seam that slips past the gate is flagged on the render itself. A tile that was never checked carries no warning, which is one more reason to check first.

Let an agent check before it renders

Over SudoMock's MCP server an assistant gets the free check as check_seams and the repair as fix_seams; have it ask you before each fix. Ask it in one message, for example: "Check these twelve pattern tiles for seams, tell me which ones need a fix, fix those after I say yes, then render each one on my tee template." check_seams returns the status and the breaking joins of each tile, so the assistant can name the tiles that need a fix and render only the ones that pass. Connect an agent covers the connection, with steps for Claude Code and Cursor, and Merch mockups with ChatGPT or Claude shows the render half of the same conversation.

Next step

Run the check on the tiles of your next collection before the first render, starting with the ones that go on large surfaces. Check and fix pattern seams walks through the check, the job and the webhook, and Artwork placement covers tile, size and fit on a PSD. To see the repeat on a product without a PSD of your own, open the throw pillow mockup templates or the wallpaper mockup templates with Use This Mockup and turn on Pattern. For tile size and spacing per product, see Pattern mockups by API.

Frequently asked questions

How do I know if a repeat pattern is seamless?

Repeat the tile at least two by two and look along the joins: a cut motif or a step in tone there means the edges do not wrap. A seam check by API runs the same test without opening the file and names the join that breaks. A tile that repeats cleanly comes back as seamless.

Why does my pattern look fine alone but show lines on the product?

A seam sits at the edges of the tile, and the edges only meet once the tile repeats. One break in the file then shows at every join, so on a large print it forms a grid. Check the tile at the cut the product uses before you render it.

Can a seam be fixed without redrawing the pattern?

Yes. A seam fix repairs the joins of a tile as a job and returns a new file at the same width and height, and a failed fix is refunded. The free check says before any charge whether the fix will take the tile.

Does checking a pattern tile for seams cost anything?

No. The SudoMock seam check is free and answers in the same call. Checking the same image again returns the first answer at once, so a whole collection can be checked before every render.

Can I check a tile that the product crops?

Yes. Send crop_aspect, the width of one tile in the render divided by its height, and the check cuts the image the way a render with fit set to crop does, then checks that cut. Leave it out to check the whole image.

Sources

  1. How to Create a Seamless Pattern (Tile) in Photoshop (opens in new tab), Julieanne Kost's Blog
  2. Check and fix pattern seams (opens in new tab)
  3. Check the seams of a pattern tile (opens in new tab)
  4. How to check a pattern tile before you render it on a mockup (opens in new tab)
  5. Connect an agent (opens in new tab)
  6. Artwork placement (opens in new tab)
B

Beck

CTO

View all posts

On this page

  • What makes a repeat pattern seamless
  • One seam becomes a grid on the product
  • Check a tile by eye in Photoshop
  • Check every tile by API before it is rendered
  • Fix a seam without redrawing the tile
  • Gate a whole collection on the check
  • Let an agent check before it renders
  • Next step
  • Frequently asked questions
  • Sources

Related articles

A seamless garden pattern tile next to the request field tile set to true, and the same pattern repeated across a ceramic mug and a throw pillow
Tutorial

Pattern Mockups by API: Repeat a Seamless Design on Your Own PSD or Photo

Repeat one seamless tile across a mug, a pillow or any smart object with one render request: set the tile size, add spacing and render a collection.

Oct 24, 2026 · 6 min read

A trellis wallpaper swatch and the fields label wall and tile true, next to the same trellis repeated across a bedroom wall behind a bed, framed prints and lamps
Tutorial

Wallpaper and Mural Mockups on Your Own Room Photo, by API

Render each wallpaper design as a repeat at its printed scale, or one mural across the wall, on your own room photo with one request per design.

Oct 26, 2026 · 6 min read

A rocket design file next to SudoMock renders of it on a white tee, a white 11 oz mug and a canvas tote, above the chat message that renders the set
Tutorial

Merch Mockups With ChatGPT or Claude: One Design on a Tee, a Mug and a Tote

One design file, one mockup per product, and one message to ChatGPT or Claude that renders the tee, the mug and the tote exactly.

Oct 22, 2026 · 6 min read

Your own PSD, rendered via API

Render your own PSD through the API. Start with 500 one-time credits, no card.

Start Free View Docs

Render your own PSD via API with 500 one-time credits.

Start Free · 500 credits, no card