
Image-editing features are easy to group under one generic action: upload, configure, generate, download. That UI sequence is not a sufficient product model. Changing an image’s camera relationship to a scene and replacing a recognizable face have different inputs, acceptance criteria, and safety requirements. If a product team lets both travel through one unnamed “edit” state, it cannot explain why a result was approved.
This is a design and QA memo, not a claim about any service’s internal implementation. The types, endpoints, and test cases below are proposals for an application that routes static-image requests through a reviewable workflow.
Start with two explicit jobs
A viewpoint job changes how the scene is read. Its inputs describe direction, framing, and lens character. A face-replacement job uses a target image and an approved source face, and it needs a permission and context check in addition to visual QA.
PictureMaker provides public image tools that make the distinction visible at the product level. A workflow can use that distinction as a useful boundary without presuming how any model, queue, or storage system works behind the interface.
For example, the public Restyle Video screen exposes left-right rotation, up-down rotation, default/wide-angle/close-up lens choices, and a preview-oriented generation step. A request contract should name those choices as a proposed direction, not as an instruction to mutate the original asset silently.
The separate Smart Shot Video screen asks for a target image and a source face image and exposes Swap Face and Swap Head modes. A responsible product contract should treat this as a static-image change that requires documented authorization and a use-context review. It must reject requests meant to deceive, impersonate, or produce non-consensual intimate content.
Model the request before a job exists
type AngleRequest = {
kind: 'angle';
assetId: string;
horizontalDegrees: number;
verticalDegrees: number;
lens: 'default' | 'wide' | 'close';
placement: 'listing' | 'editorial' | 'social';
};
type FaceRequest = {
kind: 'face';
targetAssetId: string;
sourceFaceAssetId: string;
mode: 'face' | 'head';
permissionRecordId: string;
intendedContext: string;
};
type ReviewState =
| { state: 'draft' }
| { state: 'awaitingConsent'; request: FaceRequest }
| { state: 'generating'; request: AngleRequest | FaceRequest }
| { state: 'visualReview'; candidateId: string }
| { state: 'contextReview'; candidateId: string }
| { state: 'approved'; candidateId: string }
| { state: 'rejected'; reason: string };
The interesting part is not the TypeScript syntax. It is the missing shortcut: FaceRequest cannot go directly from upload to download. A product can require a permission reference before it creates a job. AngleRequest, meanwhile, can record where the image will appear so reviewers inspect the output in an appropriate crop.
Keep generation parameters and acceptance tests separate
Parameters say what was requested. Tests say whether the candidate is fit for use. Combining them produces brittle prompts such as “make a flattering 30-degree angle with perfect lighting.” That sentence hides at least three acceptance questions.
| Job | Proposed parameters | Visual acceptance | Context acceptance |
|---|---|---|---|
| Angle | horizontal/vertical direction, lens, placement | Main subject is readable; geometry and edges remain believable | Crop supports the stated placement |
| Face | target, source, mode | Face boundary, light, expression, and hairline merit review | Permission exists; use does not imply a false event or endorsement |
The phrase “believable” is intentionally not an API response field. A human reviewer should compare the candidate with the source, at the final display size, and decide whether the visual change helps the intended use.
Test the failure paths, not just the happy path
describe('face request gate', () => {
it('does not enqueue a job without a permission record', () => {
expect(validateFaceRequest({ permissionRecordId: '' })).toEqual({ ok: false });
});
it('routes a generated candidate to visual review before export', () => {
expect(nextState({ state: 'generating' }, 'candidateReady').state)
.toBe('visualReview');
});
});
The example is pseudocode, not a product integration. Its point is to make the workflow testable. Add equivalent tests for missing target assets, disallowed request context, and a candidate that fails review. For angle work, test whether a user can compare candidates, preserve the source, and return to a revised brief instead of overwriting the original.
A release checklist
- The source and every candidate have distinct IDs and the source remains available.
- Angle requests persist direction, lens selection, and final placement.
- Face requests require an authorization record and a stated context before generation.
- Results are marked as drafts until a human has reviewed them at the final crop.
- The reviewer can reject distorted geometry, unclear faces, mismatched light, or misleading context.
- Audit logs describe the decision without storing more sensitive personal data than the workflow needs.
Make the reviewer’s decision portable
Teams often discover a candidate in one place and publish it in another. The review record should therefore travel with the asset: what was changed, what placement was evaluated, who approved a face-related request, and why a rejected alternative was not used. This is not a demand for a heavyweight compliance system. Even a concise internal note prevents a later editor from confusing an exploratory mockup with an approved source.
An image tool can feel fast without making its decisions invisible. Naming the job, preserving the source, and adding a context checkpoint gives teams a route to useful iteration while recognizing that a face is not just another layer in a design file.
Top comments (0)