How I Plan a Veo 3.1 Product Video: One Buyer Question per Shot

typescript dev.to

When I plan an AI product video, I separate five jobs: product identity,
demonstration, atmosphere, story and the final edit. I do not put them all
into one prompt.

Here is the shot-manifest template I recommend before calling the video API.
It is a design proposal with illustrative examples, not a report of a paid
generation experiment or a customer result.

Disclosure: I work on XPLA. The XPLA fields below describe the contract I
checked against the public documentation on September 4, 2026. This is not a price, speed, access or fidelity
guarantee.

One shot owns one buyer question

“Make a premium product ad” is not a testable requirement.

“Show where the touch control is and what changes after one tap” is.

I split a sequence into:

  • evidence — establish product identity;
  • action — show one mechanism;
  • context — show where the product is used.

The evidence shot runs first. If the product is wrong in a restrained shot, I
do not spend more generations adding hands, moving props and dramatic camera
motion.

The manifest

type ReviewState = "draft" | "approved" | "submitted" |
  "completed" | "accept" | "repair" | "reject";

type ShotManifest = {
  shotId: string;
  role: "evidence" | "action" | "context";
  buyerQuestion: string;
  referenceMode: "frame" | "ingredient";
  mustPreserve: string[];
  allowedMotion: string[];
  prohibitedImplications: string[];
  acceptIf: string[];
  repairIf: string[];
  rejectIf: string[];
  state: ReviewState;
};
Enter fullscreen mode Exit fullscreen mode

Example:

const shot: ShotManifest = {
  shotId: "sku-014-action-01",
  role: "action",
  buyerQuestion: "What does the closure look like in use?",
  referenceMode: "frame",
  mustPreserve: ["cap shape", "label geometry", "bottle color"],
  allowedMotion: ["slow hand approach", "small camera push"],
  prohibitedImplications: ["leakproof unless verified"],
  acceptIf: ["closure visible", "label readable"],
  repairIf: ["crop hides contact point"],
  rejectIf: ["cap, label or product count changes"],
  state: "approved"
};
Enter fullscreen mode Exit fullscreen mode

The prompt is derived from this record. The QA decision returns to the same
record.

I enforce a motion budget

Each shot has three motion variables:

  1. product or hand action;
  2. camera movement;
  3. environmental movement.

Only one gets to be high variance.

If a hand performs a precise mechanism, the camera and background stay quiet.
If the camera performs an orbit, the product stays still. This is not a model
rule; it is an application rule that makes failures explainable.

I validate the model contract separately

The current XPLA public model is veo-3.1-fast on POST /v1/videos.

Its verified wrapper accepts:

  • fixed eight-second tasks;
  • 720p or 1080p;
  • 16:9 or 9:16;
  • up to two ordered frame references;
  • up to three ingredient references.

Reference-video input is unsupported. Google's native Veo API has a different
request shape, so I do not copy native provider fields into this wrapper.

function validateShot(s: ShotManifest) {
  const errors: string[] = [];

  if (!s.buyerQuestion.trim()) errors.push("Missing buyer question");
  if (s.mustPreserve.length === 0) errors.push("Missing product truth");
  if (s.allowedMotion.length > 2) errors.push("Motion budget too broad");

  const outcomes =
    s.acceptIf.length + s.repairIf.length + s.rejectIf.length;
  if (outcomes === 0) errors.push("Missing review rules");

  return errors;
}
Enter fullscreen mode Exit fullscreen mode

A timeout is not a new creative

The API task is asynchronous. I persist the intent before submitting:

type GenerationRecord = {
  shotId: string;
  intent: "first_calibration" | "repair" | "new_creative";
  requestHash: string;
  taskId: string | null;
  state: "approved" | "submitted" | "transport_unknown" |
    "completed" | "failed";
  attempt: number;
  nextAction: "submit" | "poll" | "reconcile" | "review";
};
Enter fullscreen mode Exit fullscreen mode

If the client times out, the state becomes transport_unknown. The application
reconciles the original task before creating another generation.

That distinction matters because a timeout does not prove the first task never
started.

Product QA runs before cinematic review

My review order is:

  1. identity;
  2. geometry and count;
  3. label and text;
  4. mechanism and contact points;
  5. physical plausibility;
  6. crop and channel fit;
  7. lighting and rhythm.

The outcome is explicit:

  • accept — the shot answers its question and preserves product truth;
  • repair — the product is correct and a local layer can be fixed;
  • reject — the product, mechanism, count, label or claim changed.

A technically completed task is not publication approval.

The final ad is an edit

An eight-second generation is a production unit, not necessarily the delivery
length.

I may trim an evidence clip to two seconds, an action clip to three and a
context clip to three. Captions, approved voice, licensed sound and the CTA
belong in the editing timeline.

No paid generation was run for this article, and the diagram is a workflow
explanation—not video evidence.

The current wrapper details and request examples are in the
XPLA Veo 3.1 Fast guide.
That page currently uses noindex,follow; I am linking it for documentation,
not claiming it is indexed or ranked.

My stop rule is simple: if the first evidence shot changes a non-negotiable
product fact twice, I return to the source material instead of growing the
batch.

Source: dev.to

arrow_back Back to Tutorials