Disclosure: This is an AI-generated educational article and original code example, prepared for an authorized ClipRoam distribution task. It does not upload portraits, call the product API, or claim a completed paid-generation test.
A short AI-video form mixes two different decisions: what the user wants to create, and whether the user wants to pay the actual quoted cost. A client-side checklist can help with the first decision without pretending to answer the second.
Consider a scene with two portraits. “Make them interact” leaves several things unspecified: which person takes which role, what action should happen, and whether the duration leaves room for it. Explicit fields make those omissions visible before an upload or generation request.
Keep the planner independent of billing
This pure function validates a small plan. It uses no network requests and stores no data. The allowed durations and qualities are illustrative UI options, not a substitute for a service's current capabilities.
export function validateVideoPlan(input = {}) {
const plan = input ?? {};
const text = value => typeof value === "string" ? value.trim() : "";
const issues = [];
if (!text(plan.leftRole)) issues.push("Define portrait 1's role.");
if (!text(plan.rightRole)) issues.push("Define portrait 2's role.");
if (!text(plan.action)) issues.push("Describe one visible action.");
if (![5, 10].includes(plan.duration)) {
issues.push("Choose a supported duration.");
}
if (!["720P", "1080P"].includes(plan.quality)) {
issues.push("Choose a supported quality.");
}
if (plan.hasPortraitPermission !== true) {
issues.push("Confirm permission before uploading portraits.");
}
if (plan.willReviewQuote !== true) {
issues.push("Review the actual quote before generation.");
}
return { readyForReview: issues.length === 0, issues };
}
The return value deliberately says readyForReview. A valid object is neither proof of consent nor authorization to spend credits. In a production app, the server must still authenticate the relevant action, validate the upload and settings, obtain an authoritative quote, and require the appropriate confirmation before creating a paid job.
Notice that the two checkbox values require the boolean true. Strings such as "false" and "true" are both truthy in JavaScript, so a generic truthiness check would hide a common form-integration mistake. Likewise, the example expects numeric durations: normalize your UI input deliberately rather than silently accepting arbitrary strings.
Two small examples
validateVideoPlan({});
// readyForReview: false, with seven actionable issues
validateVideoPlan({
leftRole: "human partner",
rightRole: "fictional zombie partner",
action: "They turn toward each other and share a gentle hug.",
duration: 5,
quality: "1080P",
hasPortraitPermission: true,
willReviewQuote: true
});
// { readyForReview: true, issues: [] }
An empty plan should produce useful next actions. A complete plan should preserve the two role assignments. It should not infer a price from the duration or turn the checkbox into a claim that the service has verified the user's rights.
Give validation a clear place in the interface
Render the issues as text beside the form, and use an aria-live="polite" status region for the resulting summary. Preserve the entered values when a check fails. If the user changes a setting after receiving a quote, treat the old quote as belonging to the old settings; obtain a fresh one before confirming generation.
The product context for this example is ClipRoam's public two-portrait workflow. It offers a studio duet or gentle zombie reunion, five- or ten-second landscape videos, and 720P or 1080P output. Uploads and quotes are free, while generation uses one-time paid credit packs starting at USD 8. The public site describes a three-day window for video downloads.
That download window belongs in the post-generation experience, alongside the real job status and download action. It does not belong in a planner as a fabricated expiry timestamp: the example has not created a job and therefore has no download deadline to calculate.
The useful boundary is concrete: the planner improves an incomplete request; the service provides the actual quote and job state. Keeping those responsibilities separate makes both the UI and its claims easier to inspect.
Top comments (0)