Loops de movimento contínuos em código, com seu sujeito do Scenario MCP
Visão Geral
Aqui, um loop é uma função pura do tempo. draw(ctx, w, h, t, P) pinta o quadro no instante t segundos, e cada movimento nele se repete com um período que divide a duração do loop (12 s), então o quadro em 12 s é o quadro em 0 s e o clipe se repete sem costura. Nada é gerado: nada distorce ou pisca, mudar uma cor o renova, e o mesmo código renderiza em qualquer tamanho. A exploração Motion Loops em scenario.com mostra 80 loops feitos dessa forma (40 fundos, 40 animações de formas), cada um com seu código. scripts/loop-template.html carrega os mesmos helpers (M.*), paleta (P) e registro tile(...) com os quais esses loops foram escritos, então o código dos tiles roda nele sem alterações.
O Scenario MCP faz o que o código não pode desenhar: o sujeito do usuário. Um mascote, produto ou personagem sai do Scenario como um recorte em fundo transparente, e a página do loop o desenha sobre o loop no próprio relógio do loop, então ele recebe o mesmo motion blur e a composição ainda se repete. Para um sujeito que realmente se move, um clipe de vídeo de IA é gerado a partir desse recorte, seu fundo removido no Scenario, e o clipe sobreposto ao loop renderizado com ffmpeg. O loop em si nunca precisa de um modelo e não custa nada para renderizar.
Requer Node 18 ou superior, Playwright (npm install playwright, depois npx playwright install chromium; ou --channel chrome com o Google Chrome instalado), ffmpeg e ffprobe. O Scenario MCP é necessário apenas para o sujeito. Conexão, escolha de modelo e o loop de geração: a habilidade scenario se estiver instalada, caso contrário references/scenario-mcp.md.
Referência Rápida
cp scripts/loop-template.html loop.html # um loop por arquivo: configurações, draw(), overlay
# abra loop.html no navegador: pré-visualização ao vivo; ?t=3 congela, ?tone=accent ou ?tone=light muda o tom
node scripts/render-loop.mjs loop.html --check # determinismo e costura do loop, sem vídeo
node scripts/render-loop.mjs loop.html --stills look --at 0,3,6,9 # stills para examinar
node scripts/render-loop.mjs loop.html --out loop.mp4 # 12 s, 1920x1080, 24 fps
node scripts/render-loop.mjs loop.html --params "overlay=subject.png" --out loop.mp4 # com um recorte
node scripts/render-loop.mjs loop.html --width 1080 --height 1920 --out loop-9x16.mp4 # vertical
node scripts/render-loop.mjs --qa loop.mp4 composite.mp4 # verificação de costura e formato de qualquer MP4
Execute a partir de uma pasta onde o Playwright está instalado. Arquivos existentes nunca são sobrescritos sem --force. A verificação da página renderiza o mesmo momento duas vezes (deve ser igual), compara o quadro exatamente em 12 s com o quadro em 0 s, e compara o passo ao redor do ponto de costura com o movimento ao seu redor e nos outros limites do ciclo. Uma renderização se recusa a codificar a menos que imprima PASS; --ignore-seam é apenas para um corte projetado para ficar no ponto de costura.
| Regra | Porquê |
|---|---|
Cada período divide 12 s (1, 1.5, 2, 3, 4, 6, 12); use M.phase(t, period, offset) | o quadro em 12 s é igual ao quadro em 0 s |
| Scrolls movem um número inteiro de repetições do padrão por período | uma repetição fracionária pula na costura |
Aleatoriedade apenas de M.rand(i, salt); sem Math.random, Date ou estado entre quadros | motion blur e as verificações renderizam quadros fora de ordem |
Tamanhos a partir de u = h / 100, contagens a partir de w | correto em 16:9, 9:16, 1:1 e em tamanho de miniatura |
Cores apenas de P (bg, fg, fg2, mid, accent, paper, ink), três tons por cor de marca | renove mudando BRAND; contraste mudando tom |
Easing de M.ease, com antecipação, overshoot e pausas; velocidade constante apenas para scrolls | movimento projetado, não movimento mecânico |
Configurações de renderização com as quais os 80 loops foram enviados e os padrões do script: 24 fps, 8 sub-quadros de motion blur com obturador de 180 graus, supersampling 2x, H.264 High, CRF 16, 4:2:0, BT.709 faixa limitada, faststart. Padrões que fecham o loop, truques de profundidade e hábitos de revisão: references/loop-craft.md.
| Etapa do Scenario MCP | Chamadas |
|---|---|
| Conectar, escolher time e projeto | teams_list (pergunte ao usuário quando houver vários) |
| Trazer a arte do próprio usuário | upload_asset, curl PUT de cada parte, upload_asset_complete |
| Escolher um modelo | recommend (txt2img, img2img, img2video, video2video), ou search |
| Ler suas entradas | model_schema_get |
| Precificar, depois executar após o ok do usuário | model_run com dry_run: true, depois model_run e jobs_wait |
| Buscar o resultado | asset_download, depois curl -L -o |
Exemplo Prático: Um mascote de marca flutuando sobre um loop codificado
Objetivo: um loop contínuo de 12 segundos 1920x1080 nas cores da marca com o mascote da marca flutuando nele, e opcionalmente uma versão onde o mascote acena.
-
Conectar. Chame
teams_list. Se vários times ou projetos retornarem, pergunte qual usar, e passe seuteam_ideproject_idpara cada chamada posterior: com uma conta logada,search,model_schema_getemodel_runse recusam a executar sem eles. -
Construa o loop primeiro (local, gratuito).
cp scripts/loop-template.html mascot-loop.html, definaBRAND.accentcom a cor da marca e mantenha o tile de exemplo (Perspective Floor, uma grade fluindo em direção à câmera) ou escreva seu própriodraw(). Abra o arquivo para pré-visualizar, depois:node scripts/render-loop.mjs mascot-loop.html --check node scripts/render-loop.mjs mascot-loop.html --stills look --at 0,3,6,9Veja os stills.
--checkdeve terminar comPASS. -
Traga o mascote. Se o usuário o tem como arquivo, faça o upload:
{ "file_name": "mascot.png", "content_type": "image/png", "kind": "image", "file_size": 482113 }(
file_sizedewc -c mascot.png.) Faça PUT da parte para a URL retornada com curl, depois chameupload_asset_completecom{"upload_id": "<id do upload>"}e mantenha o id do asset. -
Escolha um modelo.
recommendcom:{ "capability": "img2img", "prompt": "O mascote da imagem de referência, corpo inteiro, vista três quartos, uma pose flutuante leve, recortado em fundo transparente com bordas limpas, sem sombra, sem texto", "limit": 5 }Sem arquivo, use
"capability": "txt2img"e descreva o mascote. Senext_step.typeforask_user, mostre as opções e aguarde. Prefira um modelo cujo esquema tenha uma opção de fundo transparente; caso contrário, planeje uma etapa de remoção de fundo após. -
Leia o esquema e precifique.
model_schema_getcom{"model_id": "<id do recommend>"}. Construa os parâmetros a partir do esquema: o campo de imagem de referência recebe o id do asset carregado (como um array se o esquema assim o disser), e a opção de fundo transparente é definida. Depois:{ "model_id": "<id do recommend>", "dry_run": true, "parameters": { "prompt": "<o prompt acima>", "<campo da imagem de referência>": ["<id do asset do mascote>"], "<campo do fundo>": "transparent" } }Informe o preço ao usuário e aguarde a autorização.
-
Execute e baixe.
model_runcom os mesmos parâmetros e"wait": false, depoisjobs_waitcom{"job_ids": ["<id do job>"]}. Depoisasset_downloadcom{"asset_id": "<id do asset>", "format": "png"}ecurl -L -o subject.png "<url>"na pasta demascot-loop.html. Abra o PNG sobre a cor de fundo do loop em 100 %: halos no contorno aparecem em tons escuros; regenere em vez de escondê-los. -
Componha no canvas e renderize.
node scripts/render-loop.mjs mascot-loop.html --params "overlay=subject.png" --stills look --at 0,0.75,1.5,2.25 --force node scripts/render-loop.mjs mascot-loop.html --params "overlay=subject.png" --out mascot-loop.mp4 --psnr 4drawOverlay()faz o mascote flutuar com um balanço de 3 segundos e uma oscilação de 6 segundos com uma sombra de contato, todos os períodos dividindo 12, então a composição ainda se repete; ajuste seu tamanho e posicionamento aí. O script verifica a página, renderiza 288 quadros, codifica e verifica o ponto de costura do arquivo.--psnrcompara um quadro codificado com sua renderização sem perdas. -
Opcional: um clipe onde o mascote se move.
recommendcom"capability": "img2video", o id do asset do recorte como imagem inicial e um prompt como "o mascote acena e vira a cabeça, fundo plano liso, câmera fixa, sem cortes". Esquema, dry run, ok, executar,jobs_wait, baixar. Depoisrecommendcom"capability": "video2video"e "remova o fundo deste clipe, mantenha o sujeito com canal alfa", escolhendo WebM VP9 com alfa como saída. Esquema, dry run, ok, executar, baixar. Renderize o loop mais uma vez sem--params overlay=...(--out loop-plain.mp4) e sobreponha o clipe com ffmpeg (o comando está em references/scenario-mcp.md). A composição tem a duração do clipe; não é um loop contínuo a menos que o clipe também se repita. -
Entregue o HTML (o loop permanece editável), o MP4, os stills e qualquer composição.
Erros Comuns
- Um salto na costura em 12 s. Um período que não divide 12 (um ciclo de 5 s), ou um scroll que move
2.5 repetições.
--checkrelataSEAM JUMP(o quadro em 12 s difere do quadro em 0 s). Corrija o período; nunca faça crossfade nas extremidades. - Estado,
Math.randomouDateem um tile. O mesmotdá quadros diferentes, os sub-quadros do motion blur discordam e o loop não fecha.--checkrelataNOT DETERMINISTIC. Calcule tudo a partir deteM.rand(i, salt). - Helpers de cor que só leem hex.
P.mideM.mixColorretornam stringsrgb(), e um analisador só de hex as transforma silenciosamente em preto. OM.rgbaeM.mixColordo template leem ambos. - Estroboscopia em movimentos rápidos. Oito sub-quadros não são suficientes para um empurrão de quadro inteiro;
mostra cópias escalonadas. Um swipe de página inteira na construção precisou de 40. Aumente
--samplespara loops muito rápidos. - Um wireframe que parece poluição visual. Uma malha de onda 3D fez isso; reconstruída como linhas de cumeeira ocultas (cada linha preenche o fundo abaixo de si, desenhada de longe para perto) parece terreno.
- Dividir por profundidade duas vezes. Uma projeção que escala a distância focal pela profundidade novamente encolhe a
cena para o centro. Projete uma vez com
M.proj. - Revisar um ciclo de 3 segundos com stills a cada 1.5 s. Isso mostra duas poses dele. Amostre dentro
de um ciclo e em ambos os lados do ponto de costura (
--at 11.9,11.95,0,0.05). - Tratar cada bandeira como um bug. Um estalo projetado (um pop, uma explosão) ou uma pausa no ponto de costura pode disparar um detector de costura ou falha. Olhe para os quadros primeiro. O script compara o ponto de costura com o movimento ao redor e com os outros limites do ciclo, o que evita a maioria destes: todos os 80 loops da construção passam.
- Um rótulo ou contador que envolve errado. Qualquer coisa indexada por ciclo deve envolver com
M.mod; na construção, um contador de páginas lia "06 / 05" no ponto de costura até que corrigiu. - Baixo contraste em um tom. Mude o tom (escuro, destaque, claro) para esse loop em vez de adicionar uma cor.
- Um PNG de sobreposição do disco. Uma página aberta de
file://que desenha uma imagem local e lê pixels de volta falha, porque a imagem contamina o canvas.render-loop.mjsserve a pasta em um endereço local; a pré-visualização do navegador apenas exibe, então não é afetada. - Texto antes da fonte carregar. O texto do Canvas não espera por fontes da web; aguarde
document.fonts.load(...)antes do primeiro quadro, ou não desenhe texto em loops. - Perseguir taxa de bits. Em cor chapada, o x264 gasta muito poucos bits e o arquivo parece pequeno. Na
construção, o PSNR mostrou que o codificador adiciona quase nenhuma perda; a única perda real é 4:2:0 na croma em
linhas finas e saturadas. Verifique com
--psnr, e engrosse linhas finas coloridas em vez de aumentar a taxa de bits. - Perder o alfa de um clipe VP9. O decodificador VP9 embutido do ffmpeg ignora alfa; coloque
-c:v libvpx-vp9antes de-i shot.webm. - Fazer o loop com um modelo de vídeo. O último quadro de um clipe gerado raramente encontra exatamente seu primeiro.
...
[truncado para tradução]