Model swap workflow: engineering handover

Exported 2026-10-20 from the model-swap skill at version 2.6.0 (skills/model-swap/, the canonical source; the copy in reference-implementation/ is a snapshot). This is the process that produced the swaps Kate Hewko approved on https://pixverse-kate-hewko-1020.pages.dev/. It is written for the team that will run it as a production workflow.

What the workflow does. Given a brand's product photo, a model's face and body references and a few words about the pose and the garment, it produces one edited copy of the photo in which the model is replaced down to the fingertips, the garment and everything else stay as photographed, an independent vision reviewer has judged the result against the original, and the deliverable has the photo's exact pixel size.

Contents of this folder:

Path What
README.md this spec
prompts/ every prompt template, rendered from the code with {PLACEHOLDERS}; review.rubric.json is the reviewer's criteria and pass rule
job.schema.json the job request and result shapes
examples/kate-hewko/ the real parameters, a rendered prompt per type, a generation receipt, two review records, two size charts, timings and costs
reference-implementation/ the Python scripts and the skill's own documentation, as shipped

1. Pipeline

model intake ──► reference set ──► size check ──► generate (one edit) ──► frame match ──► review ──► retry? ──► deliver
Stage Input Output Reference implementation
1. Model intake a comp card or photos (brand's own model) or a casting brief (fictional model) a measurement card; for a fictional model, an approved six-panel sheet model-creation.md; prompt prompts/model-sheet.six-panel.txt
2. Reference set the comp card plus an identity description in words four views: front, three-quarter, profile, full length (about 40 s, four parallel generations) ref-set.py; prompts prompts/reference-set.*.txt
3. Size check the product's size chart, the size the photo was shot in, the model's card mode: identity, refit or no_swap SKILL.md section 2
4. Generate product photo + face reference + body reference + the rendered prompt one raw image identity-swap.py / body-swap.py, prompts.py, image_model.py
5. Frame match the raw image and the product photo the master at the photo's exact size frame.py
6. Review product photo + master + three full-resolution crop pairs a record with nine scores, evidence, the worst detail, a resubmit hint, a verdict garment_review.py; prompts/review.*.txt, prompts/review.rubric.json
7. Retry a failed verdict a second review to confirm; then one resubmission with the hint appended to the prompt; at most three attempts the loop in identity-swap.py
8. Deliver the passing (or best) attempt master PNG, raw PNG, before/after JPEG, receipts, review records, the claim

2. Models and references

3. Size check

For each product photo: read the size chart, note the size the photo was shot in (page text, the brand, or the variant image), and the size the model would buy from that chart.

Model's size vs the photo Mode Prompt Reviewer mode
same size, similar build identity prompts/identity-swap.*.txt strict: the garment sits exactly as photographed
different, inside the chart refit prompts/body-refit.*.txt (adds the {BUILD} and a refit KEEP block) refit: fit judged as "the same garment at her size"
outside the chart no_swap none ask the brand for a fit-model shoot or another product

A swap never keeps the photographed body under a different model: that misrepresents her and makes a size range a lie. On a relaxed, boxy garment the identity and refit results look almost identical (Yvonne on the jacket); on a fitted piece they would not.

4. Generation

Call. pixverse create image (the PixVerse CLI; the API equivalent takes the same fields) with:

Field Value
model gpt-image-2.5-sunburst, else gemini-nano-banana-2.1; if neither is available to the account, stop. No other model.
images, in order product photo, face reference, body reference (the prompt refers to them as first, second and third image)
prompt rendered from the four blocks below; no digits anywhere
quality 1440p by default; 2160p only on an explicit request (Kate's runs were at 2160p)
aspect ratio the nearest supported ratio that is at least as wide as the photo (3:4 for a 5:7 photo); never narrower, see section 5
detail level high, GPT Image models only
count 1: one job per photo
idempotency key <job>-a<attempt>-<model>; the backend dedupes by key
timeout 1200 s polling

The prompt is four blocks, built by reference-implementation/prompts.py and exported verbatim in prompts/:

  1. CHANGE ONLY THE MODEL. Who becomes the model, part by part: face, hair, neck, shoulders, both arms from shoulder to fingertips, both hands, one consistent skin tone, no trace of the original model. For a back view, the face is not visible and the back of the head is named. Identity mode says her build matches the photographed model's; refit mode says her whole body follows the body reference and the outfit is refitted "neither slimmer nor larger than she is", with {BUILD}.
  2. KEEP THE GARMENT AS PHOTOGRAPHED. The garment description, then print at the same scale and direction, colours, fabric, seams, trims, hardware; folds and hem where they are (identity) or moving only as much as her body makes them (refit); the neckline binding and every edge crisp and uncovered; hair covering no more than the original's; other garments with their exact cut, wash and weave texture, nothing smoothed.
  3. LIGHT AND SKIN. Same studio light direction, highlights and shadows on the new skin; natural, unretouched skin, no beauty smoothing.
  4. FRAME AND POSE. Same pose ({POSE}), body and head position, head size, shoulder line, camera angle, focal length, background; nothing re-cropped or zoomed; extra canvas width is plain backdrop at the sides only.

Then the tail: no readable text or logos, and (fictional models only) "she is a fictional person and must not resemble any real or famous person".

Each block exists because an earlier, shorter prompt left a specific soft spot that the reviewer kept naming: softened collar bindings, hair wisps over the neckline, arms lit differently from the studio, smoothed denim, a frame that crept up. Keep the blocks when you port this; do not compress them back into one sentence.

Rules the generator enforces. The rendered prompt must contain no digits (the scripts refuse to run otherwise). The words "semi-sheer" and "bralette" have failed moderation; describe layering neutrally ("layered over a black top").

5. Frame match

The CLI offers fixed aspect ratios only, so a 5:7 photo cannot be produced directly. The rule (frame.py): generate at the nearest supported ratio that is at least as wide as the photo, then centre-trim the extra width and resize to the photo's exact pixel size. Only backdrop at the sides is trimmed; nothing is cut from the top or bottom, so hair and hems survive. A narrower ratio would have to lose height and is never chosen. A 2K generation that is smaller than the photo keeps its own pixels at the photo's aspect; it is never upscaled. Supported ratios used: 9:16, 2:3, 3:4, 1:1, 4:3, 3:2, 16:9.

6. Review

garment_review.py sends the reviewer the original, the master, and three full-resolution crop pairs (upper, middle, lower garment: the central band of the frame split in three), with the prompt in prompts/review.identity.txt or prompts/review.refit.txt. The reviewer returns JSON: nine criteria scored 1 to 5 with evidence, the single most visible difference, a one-sentence resubmit hint, and notes. Temperature 0.1, JSON response mode.

Criterion Critical
print_pattern yes
colour yes
construction yes
trims_hardware yes
other_garments yes
fit_drape no
pose_framing no
model_replacement yes
artifacts yes

Pass = every critical criterion scores 4 or 5 and no criterion scores below 3. Anchors: 5 identical in every inspected place; 4 a difference only a pixel comparison would find; 3 a small visible difference; 2 a clear difference a shopper would notice; 1 changed into something else.

Reviewer models, in order: gemini-4-argon, then gemini-3.8-flash. Route: the OYDN gateway first, the Gemini API as fallback; an overloaded model is retried; if none answers the job stops as "unreviewed" rather than shipping unjudged. The reviewer is not perfectly stable near the threshold, so a fail is confirmed by a second independent review before a generation is spent on a resubmission.

7. Retry loop

attempt = 1
loop:
  generate (prompt + hint if any) → raw → frame match → master
  review → record
  if pass: master is the deliverable; stop
  if fail: review again; if that passes, treat as pass; stop
  if attempt == max_attempts (3): keep the best-scoring attempt, mark NOT PASSED; stop
  hint = record.resubmit_hint with any digits stripped; attempt += 1

A resubmission is the only case in which a photo is generated twice. A photo that already has a passing result is never regenerated, and a test image that passed counts as a result.

8. Deliverables and claims

Per photo: the master PNG at the photo's exact size (<stem>-swap.png), the raw output and master for every attempt, a before/after JPEG per attempt, the generation receipt (image id, model, size, cost) and the review record per attempt. Full-resolution files go to the brand as files; the PixVerse media host downscales to 1920 px on the long side, so the page shows 1920 px copies and the masters travel separately.

The claim for every swap is "kept as photographed and checked against your photo" (plus "refitted to her" after a refit). Never "pixel-identical", "untouched" or "unchanged pixels": the frame is re-rendered, and the review plus the brand's own comparison are the proof.

9. Observed performance (Kate Hewko, Sunburst at 2160p)

Step Time Credits
Reference set, four views in parallel 37 s about 50 per view
Identity swap, generation only 52 to 60 s 50
Review verdict 2 to 3 min none (reviewer cost separate)
Body refit including review 3 to 4.5 min 50
Six-panel model sheet about 60 s 70

19 of 22 page swaps passed on the first attempt; two needed one or two resubmissions; one failure was the reviewer's, fixed by passing it the model's look. Details in examples/kate-hewko/parameters.md.

10. For production

Prompt files