Communitygithub.com

Ameetms/Claude-skill-block-toon-story-video

Crie vídeos curtos de narração em primeira pessoa no formato 9:16, em um estilo block-toon 3D (personagens com caixas arredondadas, rostos pintados, contornos a tinta, câmera sempre em movimento e legendas coloridas palavra por palavra), a partir de um roteiro ou narração, renderizados em código.

O que é Claude-skill-block-toon-story-video?

Esta skill permite que agentes de IA (como Claude Code, Cursor ou Codex) gerem vídeos de histórias em primeira pessoa no formato vertical (720x1280 ou 1080x1920, 30 fps) com duração de 30 a 130 segundos. O estilo visual é um block-toon 3D distinto, com personagens compostos por caixas arredondadas e contornos escuros, inspirado no curta "Busted by the Shoeshine Man". Tudo é gerado por código: uma cena three.js renderizada em Chromium headless, uma função `frame(t)` determinística e capturas de tela processadas via ffmpeg. A prioridade do usuário é a fidelidade do design dos personagens e a suavidade da animação. A skill inclui um pipeline completo: desde a geração de roteiro e timestamps de palavras, passando pela construção de elenco e cenário com uma biblioteca de blocos (`blockkit.js`, `props.js`), até a renderização de vídeo e mixagem de áudio. Recursos importantes: a câmera nunca fica estática (sempre com movimento eased e drift), os cortes são sempre secos (sem crossfade), e cada personagem deve ser reconhecível pela silhueta. A skill também gera folhas de referência de design e ambiente antes de renderizar o vídeo final, garantindo a qualidade visual.

Funciona com✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Ameetms/Claude-skill-block-toon-story-video/tree/HEAD

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Vídeo story block-toon (estilo "Busted by the Shoeshine Man")

Use isso quando o usuário quiser um vídeo vertical (720x1280 ou 1080x1920, 30 fps) de história em primeira pessoa, com 30-130 s, narrado, com personagens 3D em blocos arredondados, movimento contínuo suave e legendas coloridas impactantes. Tudo é código: cena three.js em Chromium headless, uma função frame(t) determinística, capturas de tela canalizadas para o ffmpeg.

A prioridade do usuário é fidelidade no design dos personagens e suavidade da animação. Não pule as verificações de personagens na etapa 5.

1. Como o vídeo de referência se parece (medido)

  • 720x1280, 30 fps, ~122 s, AAC estéreo cerca de -14 LUFS com um fundo contínuo e suave sob a narração.
  • ~47 cortes secos (cortes de quadro único, nunca crossfades), duração média do take ~2,6 s (variação de 1,2-5 s). Dentro de um take, a câmera está SEMPRE em movimento: push-in suave, pull-out, drift de grua/ângulo alto, push de ângulo baixo, whip-tilt até um teto ou janela. Menos de 1% dos quadros são estáticos.
  • Legendas no terço inferior (topo cerca de 64-68% da altura), 2-3 palavras por grupo em letras minúsculas, fonte geométrica arredondada e negrito (Poppins ExtraBold), base branca com palavras-chave coloridas (dourado #f5c32c, ciano #48c9f0, coral #ff5b4d, rosa #ff7ac0, verde #2ecc8f, laranja #ffa21f), contorno preto grosso, pequeno pop de escala em cada grupo.
  • Ambiente: interior creme/tan quente (parede #dcbf96, chão #c7aa7d, pedra #d9c39b, lambril #b99a6f, céu #c7dcec) com acentos marrom #570d0e, marinho #1c2a49, dourado #e0990d, teal #1f8f8c, vermelho #a3160f.
  • Iluminação: suave, brilhante, ligeiramente quente; sombreamento gradiente suave e sombras suaves projetadas. Sem bandas cel duras.

2. Bíblia de design de personagens (siga exatamente)

Silhueta e proporções

  • Cada parte do corpo é uma caixa arredondada. O raio do bevel é cerca de 15-18% da menor dimensão da peça. Nunca use esferas ou cápsulas para partes do corpo.
  • Cabeça: um cuboide ligeiramente mais largo que alto (0,44 x 0,41 x 0,39 unidades), cerca de 1/4-1/3 da altura da figura em closes, de modo que a figura tem ~4 cabeças de altura em planos abertos. Bloco de pescoço curto. Torso 0,46 x 0,56 x 0,26. Braços 0,27 + 0,26 (superior + antebraço). Pernas 0,30 + 0,27. Altura total cerca de 1,7 unidades.
  • Mãos são blocos de mitene rechonchudos: um bloco de palma com quatro dedos curtos de dois segmentos e um polegar separado. Elas podem se curvar de aberta para punho e se abrir. As mãos nunca devem parecer aranhentas.
  • Faixa de punho branca em cada pulso. Sapatos pretos, um bloco plano com ponta arredondada.
  • Sem quebras de junta visíveis. Onde duas caixas arredondadas se encontram em uma junta dobrada (quadril, joelho, ombro, cotovelo, punho, pescoço/torso, quadril/torso), os beveis abrem um espaço ou entalhe que parece uma quebra. Esconda cada junta sob uma camada de pano na mesma cor da roupa: uma pequena esfera (ball()) centrada no pivô da junta, do tamanho da meia largura do membro + ~0,002 e esticada ao longo do membro (sc [1,1,2-1,4,1]); um bloco de pelve unindo os dois quadris; um bloco de colar sobre a costura pescoço/torso; uma peça de punho de cor de pele sob o punho. Não superdimensione as bolas (meia largura do membro + 0,015 criou joelhos e cotovelos irregulares). Verifique com um teste de estresse de poses flexionadas (braço levantado, caminhada no meio do passo, perna levantada), com zoom.

Rosto (pintado na frente da cabeça, redesenhado a cada quadro em uma textura de canvas)

  • Olhos grandes e redondos: esclera branca, íris verde ou marrom, pupila preta, brilho branco. Linha grossa da pálpebra superior preta. Os olhos podem olhar ao redor (lookX/lookY), piscar e apertar.
  • Sobrancelhas grossas e cônicas que inclinam (zangado/preocupado) e levantam. Óculos de aro preto são muito maiores que os olhos (raio do aro cerca de 2x o raio do olho). Os óculos devem ser uma moldura conectada: os dois aros são unidos por um arco de ponte curvo sobre o nariz e cada aro tem uma linha de haste saindo para a borda do rosto. Dois aros flutuantes parecem quebrados (um usuário sinalizou isso na primeira folha de elenco).
  • Sem nariz. A boca é uma pequena linha/curva, ou uma boca aberta preenchida com língua rosa ao falar. Valor de sorriso -1..1.
  • Blush suave opcional.

Cabelo, chapéus, acessórios (blocos empilhados)

  • Herói: topete marrom com ponta pontiaguda, peças laterais e um bloco traseiro. Outros: curto, ou longo (cortinas laterais + bloco traseiro). Franja preta é um bloco angulado fino.
  • Boné de policial: bloco de coroa marinho + viseira preta + distintivo dourado. Boina: bloco marrom + aba curta + botão claro.
  • Homem mais velho: bigode de bloco branco + remendo branco na têmpora.
  • Roupas são coloridas e simples: terno (jaqueta marrom, camisa branca, gravata escura, lapelas, cordão dourado V + crachá branco com faixa azul), uniforme (marinho, distintivo dourado, cinto preto + fivela dourada), avental (camisa branca, avental marrom com botões), além de variantes cinza/verde/tan/marinho/teal para figurantes.
  • Tons de pele: pêssego #efaa71, tan #d89a62, marrom #8a5230, escuro #5a3320, claro #f4c49a. Cabelo marrom #59321a, preto #14110f.

Renderização

  • Contorno de tinta escura e fina (#1c0f06) em cada parte via um shader de casco invertido com largura constante na tela. A largura é uma fração da distância da câmera: w = px / ((H/2) / tan(fov/2)) onde px é a espessura de linha desejada em pixels da tela (cerca de 0,003 para takes de vídeo 720x1280, cerca de 1,5-2 px). Para folhas de vários personagens distantes a 1600x900 use K.setOutlineWidth(.0009), para bustos cerca de .0016; o padrão é muito grosso em uma câmera distante. Rostos e pequenas peças de acabamento pulam o contorno.
  • Material Lambert, luz hemisférica (cerca de 2,9) + um sol de sombra suave (cerca de 1,5). Sombras PCF suaves.
  • Multidão de fundo usa lod: 1 (sem dedos, menos blocos de cabelo). Nunca crie um design único por figurante; varie tom de pele, cabelo, cor da roupa e penteado.

Regra de variedade: todo personagem nomeado deve ser reconhecível apenas pela silhueta (chapéu, forma do bloco de cabelo, óculos, bigode, tom de pele, cor da roupa). Use as mesmas proporções para todos.

Folhas de referência (faça isso quando o usuário pedir um design de personagem ou ambiente, antes de qualquer vídeo)

Construa um designsheet.html e um envsheet.html ao lado de scene.html (mesmo kit, mesmo render.cjs, execute node render.cjs designsheet.html out 0,1,2 --w 1600 --h 900). frame(t) escolhe um modo com Math.round(t); os rótulos são uma sobreposição DOM (Poppins) posicionada projetando pontos 3D com new THREE.Vector3(x,y,z).project(camera); o título da página e as amostras também são DOM.

  • Arquivo de elenco cast.js: uma tabela DEF (nome, função, 4 amostras [pele, cabelo, roupa, acento]), uma tabela BUILD de um construtor por personagem (makeChar + alguns box() extras de acessórios), makeOne(name), makeCast(), e pose(name, C) que redefine o rosto e a pose a cada quadro e aplica uma pose limpa de folha de modelo. Torne cada personagem único pela silhueta: diferentes scale/headScale, penteado, chapéu, óculos, bloco de bigode, tom de pele e uma cor de acento.
  • Folha 0 lineup: todos os personagens em uma fileira (câmera sobre [0,1.02,15], fov 16,5), nome + função + quadrados de amostra abaixo de cada um. Folha 1 turnaround do protagonista em yaw 0, .75, PI/2, PI (frente, 3/4, lado, costas). Folha 2 expressões: seis bustos (neutro, feliz, zangado, surpreso, preocupado, presunçoso) desenhados como tiles de tesoura, porque empilhar seis personagens em uma cena 3D coloca linhas sob o chão e sobreposição. Padrão de tile: renderer.autoClear=false; renderer.setScissorTest(true); então por tile setViewport(x, H-y-h, w, h); setScissor(...); renderer.clear(); camera.aspect = w/h; camera.updateProjectionMatrix(); renderer.render(scene, camera); e redefina o viewport, o teste de tesoura e autoClear no final de frame.
  • Convenção de sinal de sobrancelha: face.brow = [altura, inclinação, arco], inclinação > 0 = pontas internas para baixo (zangado), inclinação < 0 = pontas internas para cima (preocupado). Em drawFace isso é ang = -s * f.brow[1] * .55. (A primeira versão tinha invertido e um policial zangado parecia triste.)
  • Folha de ambiente 0: quatro tiles de tesoura 760x318 (herói em plano aberto da entrada, parede final com janela em arco, canto do objeto principal, uma grua de ângulo alto com hall.ceiling.visible = false), cada um legendado; posicione o elenco no cenário para escala e faça-os enfrentar a câmera ou um ao outro (verifique yaw: yaw 0 enfrenta +z em direção a uma câmera em +z; um personagem de costas para a câmera é um bug de posicionamento). Folha 1: cada objeto sozinho em um palco de objetos distante (x = 400 + i*20) para que nunca apareça em takes do salão, tiles 486x300. Folha 2: planta baixa vista de cima com up = [-1,0,0] (o eixo longo corre horizontalmente), câmera sobre [-1,120,-13] olhando diretamente para baixo, fov estreito (cerca de 9,3) e rótulos de alfinete projetados de pontos do mundo. Inclua sempre uma faixa de paleta (10 amostras) no cabeçalho.
  • O teto e as vigas do salão vivem em um grupo exposto como H.ceiling (sombras desligadas, para que o sol ainda ilumine o salão); esconda-o para tomadas de grua e vista de cima. O texto da placa deve ser dimensionado para seu plano: uma placa de 1,9 x 0,5 usa 800 56px Poppins, não 78px (cortado).
  • Pegadinha do Three.js: Object3D.position e .rotation são propriedades somente leitura; defina componentes (m.rotation.x = ..., m.position.set(...)) e nunca Object.assign(mesh, { rotation: ... }), que lança uma exceção e para __ready.
  • Entregue os PNGs mais os arquivos .js com SendUserFile; re-renderize e re-envie cada folha após qualquer alteração no kit para que o usuário nunca tenha folhas desatualizadas.

3. Regras de suavidade de animação

  1. A animação é uma função pura do tempo: frame(t) define tudo a partir de t. Sem estado entre quadros, para que qualquer quadro possa ser renderizado em qualquer ordem ou em paralelo.
  2. Use kf([[t0,v0],[t1,v1]], t, easeFn) para cada movimento. Use easeOut para push-ins e chegadas, easeIO para movimentos de grua/whip, ease para coisas pequenas. Nunca linear para uma câmera ou membro.
  3. A câmera nunca está estática. Cada take tem posição eased + look-at + fov + alguns graus de roll, mais um drift de mão sempre ativo [sin(.5t)*.03, sin(.37t)*.02].
  4. Cortes secos apenas nas fronteiras dos takes, em uma palavra ou batida. Sem crossfades. Duração média do take 2-3 s.
  5. Camadas de ociosidade em cada personagem, o tempo todo: balanço de respiração, sway, roll de cabeça, piscadas a cada ~3-4 s (0,13 s eased), pequenos dardejos de olhos. K.idle() faz isso.
  6. Abertura da boca vem da intensidade real da narração (lipsync.py escreve env.json a 30 fps). Nunca um flap de looping.
  7. Gestos: antecipação (pequeno puxão para trás antes de um ponto/batida), overshoot (easeBack), segurar, estabelecer. Cabeças lideram, torso segue (use headYaw antes de twist).
  8. Ciclo de caminhada: pernas opostas, cada braço balança oposto à sua perna do mesmo lado, joelhos só dobram para trás (Math.max(0, knee)), bob 2x por ciclo, pequeno twist e inclinação do torso. A fase está em ciclos: use cerca de 1 ciclo/s para uma caminhada normal.
  9. Personagens nunca devem se sobrepor a móveis: posicione-os com x/z explícitos e verifique um still.

4. Pipeline

  1. Roteiro: primeira pessoa, gancho nos primeiros 3 segundos, frases curtas e impactantes, escalada, reviravolta, payoff na última linha. Cerca de 2,5 palavras/s.
  2. Narração: o usuário geralmente fornece um arquivo ElevenLabs. Se não, peça ou sintetize uma faixa temporária. Salve como voice.wav.
  3. Tempos das palavras: obtenha timestamps de nível de palavra (alinhamento forçado contra o texto do roteiro, por exemplo, pocketsphinx ou timestamps de palavras do whisper). Salve words.json como [{"w":"minha","s":0.20,"e":0.41}, ...], usando a ortografia e pontuação do roteiro (as legendas usam pontuação final para quebrar grupos).
  4. Envelope de lip-sync: python3 lipsync.py voice.wav env.json.
  5. Lista de takes: uma linha por take: hora de início/fim, o que o espectador vê, movimento da câmera, quem atua. Mire em um corte a cada ~2,6 s. Varie o enquadramento: close-up de rosto, plano médio de dois, push-in de ângulo baixo, grua de ângulo alto sobre a multidão, whip-tilt, over-the-shoulder, insert em um objeto (telefone, distintivo). Escreva os takes em SHOTS em scene.html.
  6. Construa o elenco + cenário a partir de blockkit.js / props.js (veja o código). Reutilize room(), chair(), bench(), crowd(); construa novos objetos com box() na paleta acima.
  7. Verifique stills primeiro (barato): node render.cjs scene.html outstills 1,4,7,...; olhe para closes de cada personagem nomeado, uma caminhada, um gesto, um plano aberto. Corrija antes de renderizar o vídeo.
  8. Renderize o vídeo (cerca de 1-1,7 s/quadro a 720x1280 em 2 núcleos, então 40 s é cerca de 15-25 min; execute partes em paralelo e em segundo plano):
export NODE_PATH=$(npm root -g)      # playwright é global no sandbox; caso contrário: npm i playwright && npx playwright install chromium
S=30; for i in 0 1; do (node render.cjs scene.html part$i.mp4 --from $((i*S)) --to $(((i+1)*S)) > r$i.log 2>&1 &); done   # 2 partes de 30 s; espere ambas
printf "file 'part0.mp4'\nfile 'part1.mp4'\n" > list.txt && ffmpeg -y -f concat -safe 0 -i list.txt -c copy silent.mp4
  1. Áudio + mux (fundo contínuo suave sob a narração, cerca de -14 LUFS):
D=130   # >= duração do vídeo
ffmpeg -y -f lavfi -i "sine=f=55:d=$D" -f lavfi -i "sine=f=82.4:d=$D" -f lavfi -i "sine=f=110:d=$D" -filter_complex "[0][1][2]amix=inputs=3:normalize=0,lowpass=f=500,tremolo=f=0.12:d=0.35,aformat=channel_layouts=stereo,afade=t=in:d=1[bed]" -map "[bed]" -ar 44100 bed.wav
ffmpeg -y -i silent.mp4 -i voice.wav -i bed.wav -filter_complex "[2:a]volume=0.12[b];[1:a][b]amix=inputs=2:duration=first:normalize=0,loudnorm=I=-14:TP=-1.5:LRA=7,aformat=channel_layouts=stereo[a]" -map 0:v -map "[a]" -c:v copy -c:a aac -b:a 192k final.mp4
  1. QC antes de entregar: (a) folha de contato, um quadro a cada ~2,6 s, verifique personagens/legendas; (b) verificação de movimento, diferença média de quadro em um stream cinza reduzido, espere 0 quadros estáticos:
python3 - <<'E'
import subprocess, numpy as np
W,H=90,160
a=np.frombuffer(subprocess.run(['ffmpeg','-v','error','-i','final.mp4','-vf',f'scale={W}:{H},format=gray','-f','rawvideo','-'],capture_output=True).stdout,dtype=np.uint8).reshape(-1,H,W).astype(np.float32)
d=np.abs(np.diff(a,axis=0)).mean(axis=(1,2)); print(len(a),'quadros; estáticos:',(d<.02).sum(),';picos(cortes):',(d>14).sum())
E

(c) loudness ffmpeg -i final.mp4 -af ebur128 -f null - (cerca de -14 LUFS), (d) legendas correspondem à fala. Entregue com SendUserFile (mp4 + um still de capa).

5. Setup

mkdir -p work && cd work && npm init -y >/dev/null && npm i [email protected] @fontsource/poppins
# crie os arquivos abaixo nesta pasta: blockkit.js props.js captions.js render.cjs lipsync.py scene.html
# (ou copie os arquivos prontos da pasta kit/ deste repositório, que também tem st...

[truncado para tradução]

Habilidades Relacionadas