Ao fim desta lição você sabe como UMA fábrica brand-agnóstica produz vídeo com a identidade REAL de qualquer cliente — pasta do cliente dirige tudo, modelos fixos, referências como medias ROLED (o unblock provado com a C.D), e nem um centavo sai sem --approve E --yes.
Esta lição destila o pipeline de anúncios da fábrica: identidade do cliente → shotlist de diretor → cenas → QA — com as decisões de spend-safety embutidas no código, não na disciplina do operador.
gemini_omni (vídeo) e gpt_image_2 (imagem)--image plano falhavavalidate sob medida (checks opt-in)A fábrica é brand-agnóstica e multi-tenant: sinal, brief, marca, identidade visual e restrições são INPUTS por cliente — zero mudança de código por cliente. A porta de entrada é ingestClientFolder (packages/marketing-factory/src/folder-ingest.ts): a pasta do cliente carrega um brand-profile.json CURADO (autorado do material real do cliente, nunca inventado por modelo — a escolha "determinístico + curado" do founder) com localização, personagens, figurino, cenários, paleta, voz e proibições.
A identidade não fica no papel: buildIdentityContext(brief) monta UM bloco injetável PREPENDIDO a cada prompt criativo, e os assets reais (logo/escritório/uniforme — nunca avatares) viajam como referências de imagem em cada geração. Foi assim que a fábrica rodou para advocacia, odontologia e contabilidade — provada em 3 indústrias — trocando só a pasta.
Pense como… uma gráfica com UMA prensa e um gabarito por cliente: o gabarito (pasta) traz cores, logo e regras; a prensa nunca é reajustada. Quebra: gabarito de gráfica não processa vídeo com fala — aqui o "gabarito" também dita idioma, lipsync e o que é proibido aparecer.
--assets-dir <subdir> vouched), e isExcludedDir pula clientes/contratos/processos como segunda rede. Sem o subdir, valem só os assets declarados no profile.marketing environment (runMarketingEnvironment) constrói a folha de referência do CENÁRIO real: coleta fotos e clipes da pasta (PII-safe), extractFrames amostra cada clipe de pan a 1fps nos ângulos distintos da sala, e planEnvironmentSheet pareia cada still real com um ângulo canônico (logo_wall, three_quarter, wide, entrance, detail) + um prompt de recriação que PRESERVA a sala e o logo reais — nunca inventa logo. Provado no escritório real da C.D: 2 clipes → 18 ângulos + 1 foto → 19 refs.
marketing sheets (runMarketingSheets) é a metade personagem/produto/prop: deriveAssetSheetSpecs deriva as folhas que o brief implica — personagem sem avatar travado vira folha split-frame (close-up trava o ROSTO, corpo inteiro trava o PORTE, fundo cinza) vestindo o uniforme REAL com o logo bordado preservado da referência limpa; o rosto é SEMPRE uma pessoa fictícia, nunca a likeness de quem aparece na foto do uniforme. Um par canônico feminino + masculino nasce quando existe asset de uniforme.
--flip-uniform aplica ffmpeg hflip antes de anexar (verificado na fronteira paga).# Stage 1 — ambiente (núcleo determinístico $0; escreve os stills em --out) alembic marketing environment ./clientes/cd-advocacia --assets-dir brand-assets --out /tmp/cd-env # Stage 1 — sheets: plano $0 por default (sheets-plan.json, sem chamada de modelo) alembic marketing sheets ./clientes/cd-advocacia --out /tmp/cd-sheets # render real (gpt_image_2, custo estimado ANTES, cap 8): exige as DUAS flags alembic marketing sheets ./clientes/cd-advocacia --out /tmp/cd-sheets --approve --yes
buildDirectorShotlist (packages/marketing-factory/src/director.ts) transforma beats simples ({shot, action, character?, setting?, camera?, speech?, cut?}) num AdShotlist de nível diretor, emitindo as linhas na ordem de fluxo internalizada (comentário em director.ts:308-310):
| linha | o que trava |
|---|---|
| PERSONAGEM | identidade E figurino idênticos à referência — "IMAGE-ONLY: renderize SOMENTE o que aparece na referência" (director.ts:326; a adição inventada é a causa nº1 de troca de identidade) |
| AMBIENTE | o cenário EXATO da referência real — parede, móveis, identidade visual (director.ts:351) |
| AÇÃO | movimento passo a passo, específico ("never he dances") (director.ts:371) |
| CÂMERA | o enquadramento do beat (director.ts:385) |
| FALA | fala no idioma do brief com "lipsync natural" (director.ts:388) |
| MARCA | logo real @token fiel e discreto — e NUNCA uma linha de logo sem asset real (director.ts:347) |
| RESTRIÇÕES | os locks de marca do profile (director.ts:412) |
| CONTINUIDADE | o corte — e matchCut abre espelhando o fechamento da cena anterior |
@logo, @ambiente, @dra: tokens WIRED aos assets reais registrados no Stage 1. Um beat com cuts[] emite até 5 CUTs ordenados numa geração só; style por beat AUMENTA o prefixo compartilhado (a luz por cena do blog).Decisão do founder, fixada no código: vídeo SEMPRE gemini_omni (Gemini Omni Flash — pt-BR + lipsync) — DEFAULT_VIDEO_MODEL_ID = 'gemini_omni' em packages/marketing-factory/src/ads.ts:95, resolvido por resolveVideoModelId; um operador pode pinar outro via --model-id (ex.: seedance_2_0), mas o default não se discute. Imagem é gpt_image_2 (as sheets do Stage 1 rendem nele).
E a lição paga: aspect escrito no prompt é IGNORADO — o modelo devolve 16:9 e o gate de QA reprova. --aspect viaja como o parâmetro real aspect_ratio da geração (buildVideoSceneParams); o enum do gemini_omni aceita SÓ 16:9,9:16 (verificado via higgsfield model get gemini_omni; um override seedance_2_0 aceita enum mais largo). O valor passa verbatim e o modelo SELECIONADO valida — fora do enum falha fechado, sem gasto.
prompt: "…vídeo vertical 9:16…" render → sai 16:9 (modelo ignora) validate --aspect 9:16 → FAIL
alembic marketing video shots.json \
--aspect 9:16
params: { aspect_ratio: "9:16" } → 720×1280O bloqueio (até 2026-07-04): o CLI real do Higgsfield anexa referências como --image "plano" (uma lista media_input_ids) — e o gemini_omni REJEITA esse shape no POST /agents/jobs com o erro de criação medias[].GeminiOmniReferenceImageMedia.role (higgsfield-api.ts:18-21). Tradução: o modelo exige que cada referência declare um PAPEL.
O unblock: reproduzir o caminho do PRÓPRIO site via API direta — createHiggsfieldApiClient (packages/marketing-factory/src/higgsfield-api.ts) envia cada asset real como media ROLED: { role: 'image', data: { id, type: 'media_input' } } (higgsfield-api.ts:134-135). PROVADO na fronteira paga: a parede do escritório REAL da C.D + o logo apareceram no render, 720×1280 (9:16).
--model-id seedance_2_0 volta a condicionar pelo caminho do CLI.A dupla trava. Todo caminho pago nasce dry-run: "Spend-safe by construction: dryRun defaults to true … Real generation requires BOTH dryRun: false and approve: true" (ads.ts:28-31; o curto-circuito em ads.ts:245: if (dryRun || !opts.approve)). No CLI isso vira: --approve E --yes juntos, ou nunca gasta — uma flag sozinha imprime o custo estimado e para. estimateCost roda ANTES em toda cena.
QA sob medida. validateVideo (packages/marketing-factory/src/validate.ts) roda ffprobe/ffmpeg/whisper sobre o mp4 local e deriva o aspect de w:h — mas todo check de conteúdo é OPT-IN: --script liga transcript-vs-roteiro + frases obrigatórias + pronúncia da marca (script "OPTIONAL — omit it for a speechless video", validate.ts:87-91); --forbidden liga a varredura de visuais proibidos (validate.ts:104); --no-text liga o check de texto queimado no frame. Anúncio mudo, de música ou com texto proposital: omita os checks que não fazem sentido — o gate serve a QUALQUER tipo de vídeo.
O one-shot. marketing campaign (runCampaign, packages/marketing-factory/src/campaign.ts) encadeia discover → generate → validate com $0 em TODOS os estágios por default: uma run "bare" toca ZERO rede e gasta ZERO — factory offline com Higgsfield fake, e a validação fica PLAN-ONLY (os critérios que uma QA real IMPORIA, derivados do brief — nenhum artefato real existe ainda). Três cadeados opt-in: --online (research pago), --approve --yes (geração paga), e a QA real só quando houver mp4.
# Stage 3 — dry-run SEMPRE primeiro (preview de custo, $0) alembic marketing video shotlist.json --aspect 9:16 --client ./clientes/cd-advocacia # render pago: SÓ com as duas flags juntas alembic marketing video shotlist.json --aspect 9:16 --client ./clientes/cd-advocacia --approve --yes # capstone multi-tenant (3 estágios em 1 comando; $0 por default) alembic marketing ad ./clientes/cd-advocacia brief.json --aspect 9:16 alembic marketing ad ./clientes/cd-advocacia brief.json --aspect 9:16 --approve --yes # QA gate — cada check é opt-in; monte o gate do SEU tipo de vídeo alembic marketing validate out/scene-01.mp4 --aspect 9:16 --lang pt \ --script "Proteja a sua aposentadoria…" --brand "cê-dê advocacia" --forbidden "tribunal,martelo" # one-shot $0 de ponta a ponta (nenhuma rede, nenhum gasto) alembic marketing campaign request.json --out plan.json
alembic marketing video shots.json --approve (só uma flag). O que acontece?dryRun: false E approve: true (ads.ts:28-31, curto-circuito em ads.ts:245) — no CLI, --approve E --yes juntos. O default é sempre o preview de custo via estimateCost.