Gera um deck VERTICAL 9:16 (1080x1920) pronto para gravar no OBS Studio, onde cada slide declara um de três layouts: camera (webcam ao vivo em tela cheia), split (animação quadrada estilo mira-squared em cima + câmera embaixo) e full (animação vertical estilo mira-vertical). A câmera do apresentador é embutida ao vivo no slide via getUserMedia (módulo mira/mira-camera.js), sem chroma key: no OBS basta capturar a janela. Sem câmera, a área vira verde chroma #00FF00 como plano B. Use SEMPRE que o usuário disser /mira-studio, deck para OBS, deck com câmera, slide com câmera, meio a meio, câmera embutida, deck para gravar vídeo comigo falando, ou pedir slides que misturam câmera e animação num vídeo vertical.
Skill: Mira Studio (9:16 com câmera embutida, pronto para OBS)
Ordem zero — não negociável
A primeira ação é resolver deck_id = YYYY-MM-DD <slug> com a data atual e criar, de uma vez, a pasta do deck e toda a árvore interna: references/, assets/, assets/vendor/ e mira/. Nenhuma dessas pastas fica para depois. Isso acontece antes de mensagem intermediária, pergunta, leitura do deck de referência, coleta de roteiro, escolha de layout ou geração.
Cria decks verticais 9:16 para gravação de vídeo (Reels, Shorts, TikTok, videoaula) em que o apresentador aparece AO VIVO dentro do próprio slide. Cada slide declara um layout, e o usuário escolhe slide a slide, na conversa:
camera — a webcam preenche a coluna inteira (você falando).
split — quadrado 1:1 no topo com título + animação (padrão mira-squared) e a câmera preenchendo o resto embaixo (você + a metáfora).
full — animação vertical em tela cheia (padrão mira-vertical, sem câmera).
Fonte da verdade: o padrão desta skill está congelado no deck de referência (validado em 2026-07-11). Resolva o arquivo nesta ordem:
mira-templates/decks/mira-studio-demo/index.html (projeto com Mira instalado)
templates/decks/mira-studio-demo/index.html (repositório fonte do Mira)
Se nenhum existir, peça para rodar npx mira-animator update. Em dúvida sobre um valor exato, o resultado deve bater com o deck de referência.
O resultado, em uma frase
Uma coluna 9:16 central (laterais #000000) onde cada slide de CONTEÚDO (body > section) declara data-layout="camera|split|full" (capa e encerramento, sem data-layout, mantêm layout próprio): nas áreas .cam-area o módulo mira/mira-camera.js injeta o feed da webcam ao vivo (object-fit: cover, espelhado estilo selfie), nas áreas de animação valem as regras congeladas das skills irmãs, e o deck inteiro está pronto para o OBS capturar a janela sem chroma key.
Fluxo conversacional (como o usuário monta o deck)
O usuário descreve o roteiro e diz o layout de cada slide, por exemplo: "slide 1 só câmera, slide 2 meio a meio sobre X, slide 3 só animação sobre Y". Para cada slide:
camera → gere só <section data-layout="camera"><div class="cam-area"></div></section>. Nada de texto por cima (a fala é do apresentador).
split → título curto (máx. 6 palavras) + metáfora animada PENSADA PARA O QUADRADO (radial/orbital/hub rende mais) + .cam-area embaixo.
full → título curto + metáfora animada PENSADA PARA O RETRATO (eixo dominante vertical: fluxo desce, comparação empilha).
Se o usuário não declarar o layout de um slide, pergunte. A capa é opcional (deck de gravação pode começar direto no primeiro slide do roteiro); quando houver capa, ela segue a diretiva do título com text-wrap: balance.
Dimensão
O quadro é 9:16 cravado e generalista para a tela: --fmt-w: calc(100vh * 9 / 16), --fmt-h: 100vh (numa tela 1080p, ~607x1080; o OBS recorta a coluna e grava em 1080x1920). Não fixe pixels. Diferente do mira-vertical clássico (100vw/3), aqui a proporção exata importa porque a saída é vídeo 9:16.
As regras herdadas (não reinvente)
Área de animação do split: é um quadrado (aspect-ratio: 1/1, lado = largura da coluna) com área segura proporcional de 4.63% (50/1080), título dentro no topo e animação preenchendo o resto com casarPalco + fitToArea (código canônico em agents/mira-squared/SKILL.md). Vale o CRITÉRIO Nº 1: a animação preenche a maior parte do quadrado.
Slide full: título no topo (máx. 2 linhas, IIFE fitTitles), palco ocupando todo o resto, metáfora com eixo vertical, casarPalco + fitToArea (playbook de composição em agents/mira-vertical/SKILL.md).
Regra Zero: toda animação tem loop interno infinito com generation counter (window.__slugGen).
Padrão criativo do agents/mira-animator/SKILL.md: metáfora primeiro, animação depois (método A/B antes de codar), refinamento sob demanda por slide, e espaço vazio é defeito de composição: o que a ação não usa vira cenário ambiente da própria metáfora (parado ou em deriva lenta, nunca focal).
Fonte mínima: nenhum texto renderiza abaixo de 13px (SVG: font-size >= 24 para W = 960).
Cor: laranja da marca #FF904D; sem arco-íris.
Todo deck: os 5 módulos em mira/ referenciados antes de </body>, nesta ordem: mira-edit.js, mira-edit-free.js, mira-draw.js, mira-camera.js, mira-record.js. Libs vendoradas em assets/vendor/.
O módulo mira/mira-camera.js (contrato)
Fonte canônica em templates/authoring/mira-camera.js; copie para mira/ do deck. O que ele garante:
Stream único por sessão: um só getUserMedia({video, audio: false}) memoizado; todas as .cam-area compartilham o mesmo MediaStream (uma permissão, sem flicker). Cada .cam-area é um SINK <video> separado desse stream único — o stream nunca é duplicado, mas os elementos de vídeo sim.
Escalabilidade (muitos slides de câmera): com mais de 2 .cam-area, o módulo anexa o stream só nas câmeras do slide visível (e vizinhos, via IntersectionObserver) e solta ao sair, mantendo ~O(1) sinks ativos mesmo em decks de 10/30 slides de câmera (evita 30 texturas de vídeo ociosas). O stream/permissão continua único; só o srcObject dos <video> é ligado/desligado. Deck com ≤2 câmeras anexa tudo (custo desprezível). A gravação é indiferente ao total de slides: captura só a coluna do slide visível e encoda no Worker.
Vídeo sempre mudo: o áudio da gravação é do OBS/microfone.
Fallback verde chroma: sem câmera (contexto file://, permissão negada, sem dispositivo), cada .cam-area ganha .cam-fallback (fundo #00FF00 PURO, nada por cima) e um aviso discreto aparece FORA da área, sumindo em 5s. Plano B: filtro Chroma Key do OBS.
Tecla C: alterna espelhamento (body.cam-mirror, padrão LIGADO, estilo selfie). Fica quieto durante os modos E/P e digitação.
Encerramento: tracks paradas no pagehide.
A skill NÃO reimplementa nada disso: só marca as áreas com .cam-area e inclui o script.
O módulo mira/mira-record.js (gravação nativa, sem OBS)
Fonte canônica em templates/authoring/mira-record.js; copie para mira/ do deck. Painel de gravação no lado DIREITO da tela (fora da coluna, portanto fora do vídeo):
Grava SOMENTE a área dos slides: captura a própria aba (getDisplayMedia com preferCurrentTab) e tenta recortar a track para a coluna 9:16 via Region Capture (CropTarget.fromElement + track.cropTo). O Worker nunca confia só na Promise: valida displayWidth/displayHeight de cada frame. Entrada 9:16 segue direta; full-tab é recortada pelas coordenadas normalizadas no OffscreenCanvas; se a proporção do frame já não corresponder ao viewport congelado, a fração incompatível é descartada e entra um crop central 9:16 seguro. Nunca estique o frame. Saída H.264 avc1 com resolução constante por sessão: 1080x1920 em Alta ou a resolução 9:16 nativa em Desempenho.
Pipeline em Worker (desempenho — a razão de não travar): todo o caminho captura→escala→encode→mux roda fora do main thread, num Worker dedicado. MediaStreamTrackProcessor puxa VideoFrames direto da track recortada (sem <video>, sem requestVideoFrameCallback, sem canvas no main thread) e o readable é transferido ao Worker; lá dentro o VideoEncoder (fixo em 1080x1920, escala interna; fallback OffscreenCanvas no próprio Worker) codifica com backpressure (encodeQueueSize>=2 descarta), keyframe a cada 2 s, e o mp4-muxer faz o mux (firstTimestampBehavior: 'offset', por trilha — nuncacross-track-offset, que deslocaria o vídeo em horas). O Worker é criado por Blob URL de dentro do próprio módulo — não há arquivo .js novo para copiar no deck. O main thread só renderiza a página (câmera ao vivo + animações) e recebe o MP4 pronto no fim. É isso que mantém câmera e slides fluidos durante a gravação, com CPU ou GPU — o encoder de hardware só acelera a compressão, não a preparação do frame.
CFR (edição) — o vídeo entra no Premiere sem drift de áudio: chave no painel, ligada por padrão. O Worker põe cada frame num slot da grade de 1/FPS antes do encoder: frame fora do slot é remarcado, dois frames no mesmo slot descartam o segundo, e slot vazio é preenchido com o quadro anterior (congela; teto de 2 s, acima disso salta e contabiliza). O áudio NÃO é tocado. Por que isso existe: sem a grade, a trilha de vídeo sai VFR (timestamps de captura + descarte por backpressure) — VLC e Chrome honram PTS e tocam certo, mas editor não trabalha em VFR: o Premiere conforma o clipe numa grade fixa e cada buraco da linha do tempo vira deslocamento ACUMULADO contra o áudio AAC, pior quanto mais longo o clipe. Desligar a chave volta ao VFR de antes (menos CPU, para quem só publica direto). Custo: cada buraco preenchido é um encode a mais — o painel mostra N dup e N salto ao vivo, e o JSON de diagnóstico traz timing: {mode, dupFilled, dupDropped, gapJumped}. Isso é DIFERENTE do alinhamento inicial entre as trilhas (BUG-20260815-HYRG, corrigido em 2026-08-16). Atenção ao que este texto dizia antes e estava ERRADO: que o offset inicial "já é resolvido pelo firstTimestampBehavior: 'offset'". Não era. No mp4-muxer, 'offset' zera CADA trilha na própria origem e descarta a distância entre elas (medido: -30,4 ms numa gravação real). E trocar a constante para 'cross-track-offset' sozinha é pior: o vídeo já chega em zero pela grade CFR, então Math.min(0, ~290 s) = 0 e o áudio vai parar a minutos de distância, que é o commit 6e84363. O alinhamento agora é do gravador: mandaAoMux() leva as duas trilhas a uma origem comum antes do muxer, com guarda para relógios incomparáveis, e o desvio medido aparece no painel (A/V ±N ms) e no diagnóstico. Contrato completo no adendo _reversa_sdd/addenda/bug-BUG-20260815-HYRG-v001.md.
Três informações separadas, sem promessa de NVENC: (1) GPUs instaladas, inventário Win32 vindo de /__mira/gpus; (2) Renderer ativo, detectado pelo WebGL e escolhido pelo Chrome/Windows; (3) encoderAuto / Hardware preferido / Software (CPU), que mapeia para hardwareAcceleration (no-preference/prefer-hardware/prefer-software). GPUs instaladas NUNCA viram opções do encoder: uma página não escolhe a placa física nem confirma NVENC. O teste real de encode confirma apenas que a preferência foi aceita. Em file://, o painel explica que o inventário requer o launcher/localhost. Se o renderer continuar na integrada, oriente Configurações do Windows > Sistema > Tela > Gráficos para o chrome.exe; não automatize configuração do sistema. O mux MP4 usa assets/vendor/mp4-muxer.js; áudio do microfone usa AAC quando suportado.
Fallback de compatibilidade: navegador sem WebCodecs/MediaStreamTrackProcessor/OffscreenCanvas cai no caminho antigo — MediaRecorder sobre um canvas fixo 1080x1920 alimentado por requestVideoFrameCallback (MP4/avc1 12 Mbps, ou WebM com aviso). Só roda quando não há o pipeline em Worker.
Métricas reais ao vivo: durante a gravação o painel mostra fps efetivo · % descartado · fila do encoder · Mbps real · MB (reportado pelo Worker). É o diagnóstico honesto — se o % descartado sobe ou o fps cai de 20, é o sinal para trocar para o modo Desempenho ou checar chrome://gpu. Abaixo de ~20 fps por 3s o painel também avisa uma vez (trecho de tela estática não conta como lentidão). Em notebook, grave na tomada.
Diagnóstico de recorte e navegação: o painel registra input, crop, output, caminho direct/canvas, maior long task, gap de rAF e gap PTS na janela de cada mira-navigation. Ao finalizar, o botão salvar diagnóstico JSON permite anexar as métricas à evidência. Os limites Windows são long task ≤50 ms e gap PTS ≤100 ms na troca.
Qualidade × Desempenho: seletor no painel. Alta = 1080×1920 (padrão de reels). Desempenho = grava na resolução NATIVA da coluna (~608×1080 num display comum), ~3× menos pixels a codificar — a alavanca real para máquina fraca, independente de CPU/GPU. Resolução constante mantém o MP4 avc1 válido; o bitrate é escalado proporcionalmente.
Gravação longa — direto no disco, sem teto (padrão): a chave salvar direto no disco (ligada por padrão) faz o Worker escrever o MP4 no arquivo enquanto grava (File System Access + FileSystemWritableFileStreamTarget do mp4-muxer, com fastStart: false). Nada acumula em RAM: a gravação dura o que o disco aguentar, e o finalize() deixa de copiar centenas de MB. O usuário escolhe o arquivo uma vez, antes de começar (o showSaveFilePicker exige ativação do usuário, por isso vem antes do seletor de captura); ao parar, o arquivo já está lá — não há download. Preço honesto: sem o buffer inteiro em mãos, o índice do MP4 (moov) vai para o fim do arquivo. Parar normalmente escreve o índice e o vídeo abre em qualquer player; um travamento do navegador no meio deixa um MP4 com os dados e sem índice (ilegível sem reparo). Se o seletor for cancelado, a gravação nem começa (e o arquivo de 0 byte é removido).
Gravação em memória (fallback): sem File System Access (file://, outros navegadores) a chave fica desligada e cinza, e o mux volta a ser in-memory — com o teto real do ArrayBuffer (~2 GB): avisa por volta de ~384 MB e PARA sozinha perto de ~512 MB, que a 12 Mbps são uns 6 minutos. Nesse modo, para clipes longos, grave em partes.
Microfone opcional: toggle no painel, mixado na gravação (a câmera já está composta no slide).
Controles: botão Gravar/Parar no painel ou tecla R (quieta nos modos E/P e digitação). Ao iniciar, o usuário escolhe "Esta guia" no seletor do navegador. O arquivo baixa sozinho ao parar (mira-reels-<timestamp>.mp4, ou -PARCIAL quando houve perda no caminho de encode/leitura/flush).
Recorte da coluna: tenta Element Capture (restrictTo na seção visível) quando o deck declara window.__miraElemCapture; a track já sai 9:16 e o teleprompter fica fora do vídeo. O restrictTo é reaplicado a cada troca de slide (evento mira-navigation e scroll), senão o vídeo congela no slide anterior. Sem a flag ou sem suporte, cai no Region Capture de sempre.
O painel some em telas estreitas (a coluna ocupa tudo) e nunca aparece na gravação.
O OBS continua como alternativa (captura de janela + recorte); a gravação nativa é o caminho sem instalação.
Teleprompter que não entra no vídeo (padrão de todo deck mira-studio)
Todo deck nasce com o teleprompter em duas peças, mais o editor de overlays e a persistência no arquivo. Os blocos canônicos estão no deck de referência; copie-os como estão.
Painel lateral (#mira-prompter, tecla T): fica na margem cinza, FORA da coluna. É o editor: as quatro chaves, o texto do slide (#mp-body, contenteditable) e o botão "Salvar no arquivo". Some durante a gravação (html[data-mira-recording] #mira-prompter { display: none }) — quem se lê no ar é o overlay.
Overlay central (#tp-ov, tecla O): o retângulo que o apresentador lê, por cima da coluna (fundo preto 60%, texto branco 60%). É irmão das <section>, nunca filho — é exatamente isso que permite excluí-lo do vídeo.
Texto por slide: vem do roteiro.md na raiz do deck (seção abaixo), não do HTML. Editar no painel reflete no overlay na hora, grava no .md e persiste em localStorage['mira-tp-text'] (cópia de trabalho). O texto troca ao navegar (scroll + mira-navigation).
Element Capture (tecla G): a gravação nativa restringe a captura à subárvore da seção visível (RestrictionTarget.fromElement + track.restrictTo), então tudo que não é descendente dela — o overlay e o painel — não é pintado no vídeo, mesmo sobreposto. O deck liga o recurso declarando window.__miraElemCapture = true; sem essa flag o mira-record.js usa o Region Capture de sempre.
Editor genérico de overlays (.me-ov, tecla E): qualquer camada sobre a câmera marcada com class="me-ov" data-me-chrome data-me-key="<id>" (mais um filho <div class="me-ov-grip" data-me-chrome></div>) vira movível e redimensionável no modo E. O data-me-chrome é obrigatório: sem ele o mira-edit-free disputa o mesmo clique e seleciona o <img> interno em vez do grupo.
Salvar no arquivo (botão ou Ctrl+S): grava o estado editável de LAYOUT (posições e tamanhos dos overlays, sem o texto do roteiro) no bloco <script id="mira-studio-state" type="application/json"> do próprio index.html — em localhost por POST /__mira_save, em file:// pela File System Access API. No load, um IIFE semeia o localStorage a partir desse bloco: o arquivo é a fonte da verdade, não o navegador. No template o bloco começa {}.
Onde cada overlay mora (a regra de ouro): o que deve entrar no vídeo (logo, selo, animação sobre a câmera) fica DENTRO da <section>; o que não deve (teleprompter, painéis) fica FORA dela, como filho direto de body.
Restrições honestas (diga isto ao usuário, não prometa mais)
Excluir o teleprompter do vídeo só funciona no gravador nativo (tecla R). No OBS não: ele grava os pixels da janela, e nada exclui um overlay. Para gravar no OBS, use só o painel lateral (que já fica fora da coluna recortada).
Element Capture exige Chrome/Edge desktop recente e contexto seguro (localhost ou https). Sem suporte, o deck cai no Region Capture e o overlay some durante a gravação (fallback no CSS, via html[data-mira-recording]:not([data-mira-elemcapture])), para não vazar.
body > section { isolation: isolate } é pré-requisito: sem stacking context o Chrome aceita o restrictTo e não emite frame — o MP4 sai vazio.
Salvar por localhost exige o servidor com os endpoints (/__mira_save, /__mira_meta): num deck antigo, reinicie o launcher depois de atualizar o mira-studio-server.cjs.
Roteiro externo roteiro.md (todo deck de gravação nasce com um)
O roteiro NÃO mora mais dentro do HTML. Todo deck gerado leva um roteiro.md na raiz, ao lado do index.html: é dele que saem os slides (layout e título) e a fala de cada slide. O apresentador escreve o roteiro no editor de texto que quiser, versiona em git, e vê o resultado no deck aberto sem recarregar.
Gramática (uma linha por cabeçalho):
<intro: texto livre, documenta a gramática para o usuário>
## Slide 1 | capa | Um roteiro, *três formatos*
Fala do apresentador neste slide.
## Slide 2 | camera
Fala do apresentador neste slide.
layout (obrigatório): capa, camera, split ou full, comparado em minúsculas. Valor desconhecido cai em camera, o layout mais simples.
Título: vale em capa, split e full; ignorado em camera. *entre asteriscos* vira <span class="accent">, montado por fragmento (nunca innerHTML).
Sem campo de animação. As animações do mira-studio são AUTORAIS (metáfora escrita à mão por slide, não montada a partir de uma lista de itens). O builder cria só o palco vazio svg#sv-slide-N, com N = posição do slide no arquivo, e cada animação escrita à mão se prende ao seu palco. Palco sem animação fica vazio em vez de quebrar; avise o usuário quando o roteiro tiver mais slides do que animações autoradas.
O número do cabeçalho é rótulo, não índice, e continua sendo. Numeração duplicada ou fora de ordem não desloca texto nenhum.
Quem casa bloco com slide é a identidade, não a ordem. Cada bloco leva <!-- mira-slide-id: X --> na linha abaixo do cabeçalho e a <section> correspondente leva data-mira-slide-id="X". Com isso, reordenar os blocos no editor, reordenar os slides no modo E, ou os dois, dá o mesmo resultado: o slide anda inteiro, com palco, título e fala. Faltando id de um dos lados, cai no casamento por ordem de aparição de antes (deck antigo não precisa de migração). Detalhes em _reversa_sdd/addenda/roteiro-identidade-de-slide-v001.md.
O mira-slide-id é metadado, não fala: o parser o extrai e o mantém fora do teleprompter e do overlay lido em câmera, e a escrita de volta o reemite verbatim.
O que sincroniza e o que não:
Dado
Fonte da verdade
Quando vale
Layout, título
roteiro.md
lido uma vez, no load (mudou, recarregue)
Texto da fala
roteiro.md
ao vivo, nos dois sentidos
Posição/tamanho dos overlays
bloco #mira-studio-state no index.html
Ctrl+S
Cópia de trabalho do texto
localStorage
entre polls
Precedência no load: roteiro.md > localStorage > array SCRIPT[] embutido. O texto não entra no #mira-studio-state: duas fontes da verdade fariam o seed do load restaurar texto velho por cima do arquivo.
Como o deck consome (blocos canônicos no deck de referência):
Um IIFE antes das animações e dos <script defer> faz a leitura síncrona do .md (os módulos de câmera, gravação e edição precisam das <section> já no DOM), guarda texto bruto, intro e cabeçalhos, monta as seções e as insere antes do painel do teleprompter, removendo as estáticas.
As <section> estáticas do HTML continuam lá como fallback: em file://, sem servidor ou com parse vazio, elas SÃO o deck. A ausência do roteiro nunca produz deck em branco.
Sincronização: poll de leitura a cada 1,5 s, escrita com debounce de 800 ms, com quatro guards que não são opcionais: (1) escrita em voo ou agendada trava o poll, senão ele desfaz o que você acabou de digitar; (2) gravação em andamento trava o poll, para não piscar texto dentro do vídeo; (3) campo com foco recebe estado e overlay mas não é sobrescrito, senão o cursor salta; (4) conteúdo idêntico aborta poll e escrita.
A escrita de volta remonta o arquivo com a intro e os cabeçalhos capturados no load mais os textos atuais. Cabeçalho nunca é reescrito a partir do estado do deck.
Arquivo ausente (404) é recriado uma vez a partir dos slides e textos embutidos.
Restrição honesta: a escrita depende do POST /__mira_save. Ele existe no mira/mira-studio-server.cjs (launcher, que também cria o arquivo quando falta) e no lib/mira-serve.js (grava, mas só em arquivo que já existe). Em file:// não há leitura nem escrita: o deck usa os slides embutidos, sem erro no console e sem sincronizar.
Chrome autoral dentro da <section> (logo, selo, .me-ov que deve entrar no vídeo) precisa ser emitido pelo builder, senão a reconstrução do load o descarta.
Fontes canônicas em templates/studio/: o .bat vai para a RAIZ do deck (diretiva: raiz = index.html + launchers) e o mira-studio-server.cjs para a pasta mira/. O ciclo de vida segue o padrão comprovado do Mira Remote/mesa tática: Node em primeiro plano, navegador aberto pelo servidor somente depois de listen() confirmar readiness.
Sobe mira/mira-studio-server.cjs (Node puro): serve o deck em http://127.0.0.1:8123 (ou próxima porta livre), expõe /__mira/health e /__mira/gpus. A consulta Win32 é uma Promise cacheada com estado loading/ready/error; o painel usa retry limitado. Falha de GPU não torna o HTTP do deck indisponível. O servidor também expõe GET /__mira_meta (caminho absoluto do alvo, usado pelo rótulo do mira-edit) e POST /__mira_save (grava o HTML no disco: é o "Salvar no arquivo" do deck e o Salvar da barra do mira-edit). O /__mira_save só aceita .html/.htm/.md (o .md é a escrita do roteiro.md pelo teleprompter), só dentro do root servido (trava de path traversal) e até ~25 MB. O MIME inclui .md e .pdf (slide full com PDF em <iframe> fica em branco sem ele).
Só depois do listen() bem-sucedido, o próprio servidor abre um Chrome dedicado (--user-data-dir em %LOCALAPPDATA%\mira-studio\) com --force-high-performance-gpu. A flag é uma preferência, não garantia: Windows/driver escolhem o adaptador final e o painel separa GPUs instaladas, renderer ativo e encoder hardware preferido. Nenhuma escrita em registro ou configuração do Windows.
O Node permanece em primeiro plano até Ctrl+C. Não use start /wait chrome.exe nem mate o servidor quando o comando Chrome retornar: se o mesmo perfil já estiver aberto, o Chrome encaminha a URL ao processo existente e retorna imediatamente.
stdout/stderr ficam visíveis e os eventos do servidor também são anexados a mira/mira-studio.log. Node ausente, portas esgotadas ou servidor ausente deixam mensagem acionável; não abra uma aba destinada a loading.
Sem GPU dedicada o launcher é inócuo (a flag aponta para a única GPU); o deck continua funcionando por index.html/serve normal.
<style id="mira-formato-multi">
/* Coluna 9:16 cravada, generalista para a tela (saída OBS 1080x1920). */
:root {
--fmt-w: calc(100vh * 9 / 16); --fmt-h: 100vh;
/* Áreas seguras de plataforma (Reels + Shorts), % da largura da coluna. */
--sz-top: 27.78%; /* 300/1080 — nav do Shorts / cabeçalho do Reels */
--sz-right: 11.11%; /* 120/1080 — coluna de ações */
--sz-bottom: 40.74%; /* 440/1080 — legenda, handle, ticker de áudio */
--sz-left: 5.56%; /* 60/1080 — margem */
}
html { background: #000000; }
body { background: #000000; display: flex; flex-direction: column; align-items: center; }
body > section {
position: relative;
width: var(--fmt-w); height: var(--fmt-h); min-height: var(--fmt-h);
overflow: hidden; background: var(--mira-bg, #0d0d0f);
display: flex; flex-direction: column;
/* stacking context: EXIGIDO pelo Element Capture. Sem isto o Chrome aceita
o restrictTo e NÃO emite frame nenhum (o MP4 sai vazio). Não remova. */
isolation: isolate;
}
/* camera: webcam na coluna inteira */
section[data-layout="camera"] .cam-area { flex: 1 1 auto; min-height: 0; }
/* split: quadrado 1:1 no topo + câmera intocada no resto */
section[data-layout="split"] .split-top {
width: 100%; aspect-ratio: 1 / 1; flex: 0 0 auto;
display: flex; flex-direction: column;
padding: var(--sz-top) var(--sz-right) 4.63% var(--sz-left);
}
section[data-layout="split"] .split-top h2 { flex: 0 0 auto; }
section[data-layout="split"] .cam-area { flex: 1 1 auto; min-height: 0; }
/* full: animação vertical na coluna inteira */
section[data-layout="full"] .full-wrap {
flex: 1 1 auto; min-height: 0;
display: flex; flex-direction: column;
padding: var(--sz-top) var(--sz-right) var(--sz-bottom) var(--sz-left);
}
section[data-layout="full"] h2 { flex: 0 0 auto; }
/* palco: preenche todo o resto (viewBox casado em runtime pelo casarPalco) */
.anim-stage { flex: 1 1 auto; min-height: 0; width: 100%; }
.anim-stage svg { width: 100%; height: 100%; display: block; }
</style>
Injete também o IIFE fitTitles (auto-ajuste de título para máx. 2 linhas) e a navegação por teclado quieta durante E/P (ambos no deck de referência).
Transição padrão: dissolve fora da gravação
Todo deck mira-studio nasce com a transição dissolve (View Transitions same-document, o mesmo padrão do mira-transition-dissolve) aplicada DIRETO no index.html, sem arquivo -dissolve separado:
Bloco CSS marcado === DISSOLVE: ::view-transition-old(root), ::view-transition-new(root) { animation-duration: 0.55s; } e um view-transition-name único para CADA elemento de UI fixa (#mrc-panel, .cam-notice e qualquer outro position: fixed), senão a UI pisca no crossfade.
Na navegação, helper dissolve(jump) com fallback (if (document.startViewTransition) ... else jump()) e scrollIntoView({ behavior: 'instant' }), nunca 'smooth' ou 'auto' dentro da transição.
Durante a gravação nativa, mira-record.js marca <html data-mira-recording="true">; nesse estado a navegação chama jump() diretamente, sem startViewTransition. Antes do salto, emita window.dispatchEvent(new CustomEvent('mira-navigation', {detail:{from,to,at:performance.now()}})) para abrir a janela de métricas. Os snapshots old/new disputam a captura da própria guia e podem criar hitch/gap no MP4. Ao terminar, o atributo é removido e o dissolve volta automaticamente.
Os dois blocos estão no deck de referência; detalhes e regras completas em agents/mira-transition-dissolve/SKILL.md.
Teclas do deck (documente na entrega)
T painel lateral · O overlay central · G Element Capture · E editar (mover/redimensionar overlays) · Ctrl+S salvar no arquivo · R gravar · C espelhar câmera · P pintar · setas navegam. T/O/G ficam quietas nos modos E/P e durante a digitação.
Passos
Criar toda a estrutura — primeira ação obrigatória. Antes de perguntar pelo roteiro, ler referências, escolher layouts ou gerar qualquer arquivo, derive o slug do pedido (ou use novo-deck-studio, com sufixo anticolisão), resolva deck_id = YYYY-MM-DD <slug> e crie decks/<deck_id>/, references/, assets/, assets/vendor/ e mira/. Informe o caminho absoluto de references/. Nenhuma outra ação pode vir antes desta.
Colher o roteiro. Liste com o usuário os slides e o layout de cada um. Sem layout declarado, pergunte. O que ele vai FALAR em cada slide vai para o roteiro.md, não para dentro do HTML. Diga a ele, em uma linha, que dá para editar esse arquivo com o deck aberto: o texto aparece no teleprompter em cerca de 1,5 s.
Depois, complete a estrutura com index.html, roteiro.md, módulos em mira/, vendor em assets/vendor/ e mira-studio-windows.bat na raiz. As pastas já existentes são reutilizadas, nunca recriadas nem abandonadas.
Gerar os slides. Um bloco ## Slide no roteiro.md por slide e, no HTML, o body > section equivalente (fallback de file://) com data-layout correto; .cam-area nas áreas de câmera; animações nativas da geometria (quadrado no split, retrato no full) com casarPalco + enquadramento uma vez sobre a parte estática (reenquadrar a cada frame faz o palco reescalar junto com o que se move) e loop interno. Todo callback de d3.timer vai dentro de try/catch: uma exceção num deles congela a FILA inteira de timers do d3.
Injetar os blocos canônicos.<style id="mira-formato-multi"> (com o isolation: isolate), o builder do roteiro.md (antes das animações e dos <script defer>), fitTitles, navegação com dissolve (transição padrão), o teleprompter completo (painel + overlay + sincronização com o .md + SCRIPT[] só como fallback + chaves + editor .me-ov + bloco #mira-studio-state vazio + seed + salvar/Ctrl+S) e os cinco <script defer src="mira/..."> antes de </body> (mira-edit.js → mira-edit-free.js → mira-draw.js → mira-camera.js → mira-record.js).
Verificar. Servido em localhost: câmera nas áreas certas, permissão pedida uma vez, animações preenchendo, títulos em máx. 2 linhas. Painel lateral com as chaves T/O/G/E sincronizadas; editar o texto reflete no overlay; editar o roteiro.md no editor externo aparece no deck em ~1,5 s e digitar no painel grava no .md sem tocar na intro nem nos cabeçalhos; Ctrl+S grava posições e tamanhos, que sobrevivem ao reload. Gravando com Element Capture: ON, o overlay continua visível para você e some do MP4 — e navegar entre slides durante a gravação não pode congelar o vídeo. Em file://: áreas verdes #00FF00 puras.
Reportar. Caminho do deck, o roteiro.md como lugar de escrever a fala (editável com o deck aberto), layout de cada slide (uma linha por slide), a gravação nativa (tecla R; encoder Auto/Hardware preferido/Software no painel; launcher Windows para inventário e preferência de alto desempenho) e a receita OBS como alternativa: servir com node lib/mira-serve.js "decks/<deck_id>" (ou npx mira-animator serve), Chrome em tela cheia, Captura de Janela no OBS, recorte na coluna, gravação 1080x1920.
Edge cases (do mais comum ao menos)
Aberto em file://:getUserMedia não existe; todas as áreas de câmera ficam verde chroma e o aviso ensina a servir em localhost. O deck continua navegável e gravável (keying manual).
Permissão negada / sem webcam: mesmo fallback verde; aviso específico.
Webcam 16:9 numa área 9:16 ou quadrada:object-fit: cover corta as sobras, nunca distorce.
Título longo no split/full:fitTitles reduz até 2 linhas; o casarPalco re-casa o palco à altura restante.
Vários slides com câmera: todos compartilham o MESMO stream; trocar de slide não repete o prompt.
Tecla C durante edição (modo E) ou digitação: o módulo ignora, sem conflito.
Deck sem nenhuma .cam-area: o módulo fica inerte (não pede permissão à toa).
Checklist
Os que mais falham (cheque primeiro):
Cada slide com o data-layout que o usuário pediu, na ordem do roteiro.
split: contêiner 1:1 exato, caixa informativa 900 × 730, palco elástico e câmera com a mesma altura do baseline.
Câmera: stream único, mudo, espelhado por padrão, tecla C alternando.
Fallback: em file:// as áreas ficam #00FF00 PURO, sem texto por cima.
Teleprompter (o que mais quebra aqui):
body > section { isolation: isolate } presente (sem ele o Element Capture grava vídeo VAZIO).
Painel #mira-prompter e overlay #tp-ov-wrapfora das <section>; overlays que devem entrar no vídeo, dentro.
roteiro.md na raiz, com intro documentando a gramática e um ## Slide por <section>; os layouts citados na intro batem com os que o deck aceita.
Slides nascem do .md; sem o arquivo (ou em file://), o deck sobe com os slides padrão embutidos, sem erro no console.
Numeração duplicada ou fora de ordem nos cabeçalhos não desloca os textos.
Cada <section> tem data-mira-slide-id, pareado com o <!-- mira-slide-id --> do bloco correspondente.
Trocar dois blocos de lugar no roteiro.md e recarregar leva palco, título e fala juntos; nenhum palco <slug>-stage vira sv-slide-N.
O <!-- mira-slide-id --> não aparece no painel do teleprompter nem no overlay.
Editar o .md aparece no deck em ~1,5 s; digitar no painel grava no .md com intro e cabeçalhos intactos; digitação contínua não tem o cursor roubado pelo poll.
Durante a gravação o poll fica parado; .md apagado com o deck aberto é recriado.
Builder do roteiro ANTES das animações e dos <script defer>; animação autoral presa ao palco sv-slide-N.
SCRIPT[] continua no HTML só como fallback, e mira-tp-text NÃO entra no #mira-studio-state.
window.__miraElemCapture = true declarado (é o opt-in que liga o Element Capture no mira-record).
mira/mira-record.js é a cópia ATUAL de templates/authoring/ (tem a chave "CFR (edição)" no painel). Deck antigo sem ela grava VFR e dessincroniza no Premiere.
Bloco #mira-studio-state começa {}, com o IIFE de seed antes de qualquer leitor de localStorage.
.me-ov com data-me-chrome (senão o mira-edit-free briga pelo clique) e .me-ov-grip.
Restrições honestas ditas ao usuário: só no gravador nativo (R), não no OBS; Chrome desktop recente; localhost/https.
Transição dissolve aplicada no index.html (bloco === DISSOLVE + dissolve() na navegação; UI fixa com view-transition-name, inclusive #mira-prompter e #tp-ov-wrap).
Durante recording, navegação instantânea sem startViewTransition e evento mira-navigation emitido antes do salto.
Coluna calc(100vh * 9/16) x 100vh, laterais #000000, centralizada via flex.
mira/ com os 5 módulos e tags na ordem certa antes de </body>.
assets/vendor/mp4-muxer.js presente (encoders do painel), mira-studio-windows.bat na raiz e mira/mira-studio-server.cjs (launcher + inventário real de GPUs).
Painel separa inventário de GPUs, renderer ativo e preferência do encoder; diagnóstico JSON disponível ao final.
Loop interno em toda animação; generation counter presente.
Nenhum texto abaixo de 13px renderizados; título máx. 2 linhas.
Capa (se houver) com text-wrap: balance; sem travessão em texto visível.
Receita OBS reportada ao final.
1---2name: mira-studio3description: Gera um deck VERTICAL 9:16 (1080x1920) pronto para gravar no OBS Studio, onde cada slide declara um de três layouts: camera (webcam ao vivo em tela cheia), split (animação quadrada estilo mira-squared em cima + câmera embaixo) e full (animação vertical estilo mira-vertical). A câmera do apresentador é embutida ao vivo no slide via getUserMedia (módulo mira/mira-camera.js), sem chroma key: no OBS basta capturar a janela. Sem câmera, a área vira verde chroma #00FF00 como plano B. Use SEMPRE que o usuário disser /mira-studio, deck para OBS, deck com câmera, slide com câmera, meio a meio, câmera embutida, deck para gravar vídeo comigo falando, ou pedir slides que misturam câmera e animação num vídeo vertical.4---56# Skill: Mira Studio (9:16 com câmera embutida, pronto para OBS)78## Ordem zero — não negociável910A primeira ação é resolver `deck_id = YYYY-MM-DD <slug>` com a data atual e criar, de uma vez, a pasta do deck e toda a árvore interna: `references/`, `assets/`, `assets/vendor/` e `mira/`. Nenhuma dessas pastas fica para depois. Isso acontece antes de mensagem intermediária, pergunta, leitura do deck de referência, coleta de roteiro, escolha de layout ou geração.1112Cria decks verticais 9:16 para gravação de vídeo (Reels, Shorts, TikTok, videoaula) em que o apresentador aparece AO VIVO dentro do próprio slide. Cada slide declara um layout, e o usuário escolhe **slide a slide, na conversa**:1314- **`camera`** — a webcam preenche a coluna inteira (você falando).15- **`split`** — quadrado 1:1 no topo com título + animação (padrão `mira-squared`) e a câmera preenchendo o resto embaixo (você + a metáfora).16- **`full`** — animação vertical em tela cheia (padrão `mira-vertical`, sem câmera).1718> **Fonte da verdade:** o padrão desta skill está congelado no deck de referência (validado em 2026-07-11). Resolva o arquivo nesta ordem:19> 1. `mira-templates/decks/mira-studio-demo/index.html` (projeto com Mira instalado)20> 2. `templates/decks/mira-studio-demo/index.html` (repositório fonte do Mira)21> 3. `node_modules/mira-animator/templates/decks/mira-studio-demo/index.html`22>23> Se nenhum existir, peça para rodar `npx mira-animator update`. Em dúvida sobre um valor exato, o resultado deve bater com o deck de referência.2425## O resultado, em uma frase2627Uma coluna 9:16 central (laterais `#000000`) onde cada slide de CONTEÚDO (`body > section`) declara `data-layout="camera|split|full"` (capa e encerramento, sem `data-layout`, mantêm layout próprio): nas áreas `.cam-area` o módulo `mira/mira-camera.js` injeta o feed da webcam ao vivo (`object-fit: cover`, espelhado estilo selfie), nas áreas de animação valem as regras congeladas das skills irmãs, e o deck inteiro está pronto para o OBS capturar a janela sem chroma key.2829## Fluxo conversacional (como o usuário monta o deck)3031O usuário descreve o roteiro e diz o layout de cada slide, por exemplo: "slide 1 só câmera, slide 2 meio a meio sobre X, slide 3 só animação sobre Y". Para cada slide:32331. `camera` → gere só `<section data-layout="camera"><div class="cam-area"></div></section>`. Nada de texto por cima (a fala é do apresentador).342. `split` → título curto (máx. 6 palavras) + metáfora animada PENSADA PARA O QUADRADO (radial/orbital/hub rende mais) + `.cam-area` embaixo.353. `full` → título curto + metáfora animada PENSADA PARA O RETRATO (eixo dominante vertical: fluxo desce, comparação empilha).3637Se o usuário não declarar o layout de um slide, pergunte. A capa é opcional (deck de gravação pode começar direto no primeiro slide do roteiro); quando houver capa, ela segue a diretiva do título com `text-wrap: balance`.3839## Dimensão4041O quadro é **9:16 cravado e generalista para a tela**: `--fmt-w: calc(100vh * 9 / 16)`, `--fmt-h: 100vh` (numa tela 1080p, ~607x1080; o OBS recorta a coluna e grava em 1080x1920). Não fixe pixels. Diferente do `mira-vertical` clássico (`100vw/3`), aqui a proporção exata importa porque a saída é vídeo 9:16.4243## As regras herdadas (não reinvente)4445- **Área de animação do `split`:** é um quadrado (`aspect-ratio: 1/1`, lado = largura da coluna) com área segura proporcional de `4.63%` (50/1080), título dentro no topo e animação preenchendo o resto com `casarPalco` + `fitToArea` (código canônico em `agents/mira-squared/SKILL.md`). Vale o CRITÉRIO Nº 1: a animação preenche a maior parte do quadrado.46- **Slide `full`:** título no topo (máx. 2 linhas, IIFE `fitTitles`), palco ocupando todo o resto, metáfora com eixo vertical, `casarPalco` + `fitToArea` (playbook de composição em `agents/mira-vertical/SKILL.md`).47- **Regra Zero:** toda animação tem loop interno infinito com generation counter (`window.__slugGen`).48- **Padrão criativo do `agents/mira-animator/SKILL.md`:** metáfora primeiro, animação depois (método A/B antes de codar), refinamento sob demanda por slide, e espaço vazio é defeito de composição: o que a ação não usa vira cenário ambiente da própria metáfora (parado ou em deriva lenta, nunca focal).49- **Idioma:** `agents/_shared/idioma.md`. Proibido travessão; acentuação correta.50- **Fonte mínima:** nenhum texto renderiza abaixo de 13px (SVG: `font-size >= 24` para `W = 960`).51- **Cor:** laranja da marca `#FF904D`; sem arco-íris.52- **Todo deck:** os 5 módulos em `mira/` referenciados antes de `</body>`, nesta ordem: `mira-edit.js`, `mira-edit-free.js`, `mira-draw.js`, `mira-camera.js`, `mira-record.js`. Libs vendoradas em `assets/vendor/`.5354## O módulo mira/mira-camera.js (contrato)5556Fonte canônica em `templates/authoring/mira-camera.js`; copie para `mira/` do deck. O que ele garante:5758- **Stream único por sessão:** um só `getUserMedia({video, audio: false})` memoizado; todas as `.cam-area` compartilham o mesmo `MediaStream` (uma permissão, sem flicker). Cada `.cam-area` é um SINK `<video>` separado desse stream único — o stream nunca é duplicado, mas os elementos de vídeo sim.59- **Escalabilidade (muitos slides de câmera):** com mais de 2 `.cam-area`, o módulo anexa o stream só nas câmeras do slide visível (e vizinhos, via `IntersectionObserver`) e solta ao sair, mantendo ~O(1) sinks ativos mesmo em decks de 10/30 slides de câmera (evita 30 texturas de vídeo ociosas). O stream/permissão continua único; só o `srcObject` dos `<video>` é ligado/desligado. Deck com ≤2 câmeras anexa tudo (custo desprezível). A gravação é indiferente ao total de slides: captura só a coluna do slide visível e encoda no Worker.60- **Vídeo sempre mudo:** o áudio da gravação é do OBS/microfone.61- **Fallback verde chroma:** sem câmera (contexto `file://`, permissão negada, sem dispositivo), cada `.cam-area` ganha `.cam-fallback` (fundo `#00FF00` PURO, nada por cima) e um aviso discreto aparece FORA da área, sumindo em 5s. Plano B: filtro Chroma Key do OBS.62- **Tecla C:** alterna espelhamento (`body.cam-mirror`, padrão LIGADO, estilo selfie). Fica quieto durante os modos E/P e digitação.63- **Encerramento:** tracks paradas no `pagehide`.6465A skill NÃO reimplementa nada disso: só marca as áreas com `.cam-area` e inclui o script.6667## O módulo mira/mira-record.js (gravação nativa, sem OBS)6869Fonte canônica em `templates/authoring/mira-record.js`; copie para `mira/` do deck. Painel de gravação no lado DIREITO da tela (fora da coluna, portanto fora do vídeo):7071- **Grava SOMENTE a área dos slides:** captura a própria aba (`getDisplayMedia` com `preferCurrentTab`) e tenta recortar a track para a coluna 9:16 via **Region Capture** (`CropTarget.fromElement` + `track.cropTo`). O Worker nunca confia só na Promise: valida `displayWidth/displayHeight` de cada frame. Entrada 9:16 segue direta; full-tab é recortada pelas coordenadas normalizadas no `OffscreenCanvas`; se a proporção do frame já não corresponder ao viewport congelado, a fração incompatível é descartada e entra um crop central 9:16 seguro. Nunca estique o frame. Saída H.264 `avc1` com resolução constante por sessão: **1080x1920** em Alta ou a resolução 9:16 nativa em Desempenho.72- **Pipeline em Worker (desempenho — a razão de não travar):** todo o caminho captura→escala→encode→mux roda **fora do main thread**, num Worker dedicado. `MediaStreamTrackProcessor` puxa `VideoFrame`s direto da track recortada (sem `<video>`, sem `requestVideoFrameCallback`, sem canvas no main thread) e o `readable` é transferido ao Worker; lá dentro o `VideoEncoder` (fixo em 1080x1920, escala interna; fallback `OffscreenCanvas` no próprio Worker) codifica com backpressure (`encodeQueueSize>=2` descarta), keyframe a cada 2 s, e o mp4-muxer faz o mux (`firstTimestampBehavior: 'offset'`, por trilha — **nunca** `cross-track-offset`, que deslocaria o vídeo em horas). O Worker é criado por **Blob URL de dentro do próprio módulo** — não há arquivo `.js` novo para copiar no deck. O main thread só renderiza a página (câmera ao vivo + animações) e recebe o MP4 pronto no fim. **É isso que mantém câmera e slides fluidos durante a gravação, com CPU ou GPU** — o encoder de hardware só acelera a compressão, não a preparação do frame.73- **CFR (edição) — o vídeo entra no Premiere sem drift de áudio:** chave no painel, **ligada por padrão**. O Worker põe cada frame num slot da grade de 1/FPS antes do encoder: frame fora do slot é remarcado, dois frames no mesmo slot descartam o segundo, e slot vazio é preenchido com o quadro anterior (congela; teto de 2 s, acima disso salta e contabiliza). O áudio NÃO é tocado. **Por que isso existe:** sem a grade, a trilha de vídeo sai VFR (timestamps de captura + descarte por backpressure) — VLC e Chrome honram PTS e tocam certo, mas editor não trabalha em VFR: o Premiere conforma o clipe numa grade fixa e cada buraco da linha do tempo vira deslocamento ACUMULADO contra o áudio AAC, pior quanto mais longo o clipe. Desligar a chave volta ao VFR de antes (menos CPU, para quem só publica direto). Custo: cada buraco preenchido é um encode a mais — o painel mostra `N dup` e `N salto` ao vivo, e o JSON de diagnóstico traz `timing: {mode, dupFilled, dupDropped, gapJumped}`. **Isso é DIFERENTE do alinhamento inicial entre as trilhas** (BUG-20260815-HYRG, corrigido em 2026-08-16). Atenção ao que este texto dizia antes e estava ERRADO: que o offset inicial "já é resolvido pelo `firstTimestampBehavior: 'offset'`". Não era. No `mp4-muxer`, `'offset'` zera CADA trilha na própria origem e descarta a distância entre elas (medido: -30,4 ms numa gravação real). E trocar a constante para `'cross-track-offset'` sozinha é pior: o vídeo já chega em zero pela grade CFR, então `Math.min(0, ~290 s) = 0` e o áudio vai parar a minutos de distância, que é o commit 6e84363. O alinhamento agora é do gravador: `mandaAoMux()` leva as duas trilhas a uma origem comum antes do muxer, com guarda para relógios incomparáveis, e o desvio medido aparece no painel (`A/V ±N ms`) e no diagnóstico. Contrato completo no adendo `_reversa_sdd/addenda/bug-BUG-20260815-HYRG-v001.md`.74- **Três informações separadas, sem promessa de NVENC:** (1) `GPUs instaladas`, inventário Win32 vindo de `/__mira/gpus`; (2) `Renderer ativo`, detectado pelo WebGL e escolhido pelo Chrome/Windows; (3) `encoder` **Auto / Hardware preferido / Software (CPU)**, que mapeia para `hardwareAcceleration` (`no-preference`/`prefer-hardware`/`prefer-software`). GPUs instaladas NUNCA viram opções do encoder: uma página não escolhe a placa física nem confirma NVENC. O teste real de encode confirma apenas que a preferência foi aceita. Em `file://`, o painel explica que o inventário requer o launcher/localhost. Se o renderer continuar na integrada, oriente Configurações do Windows > Sistema > Tela > Gráficos para o `chrome.exe`; não automatize configuração do sistema. O mux MP4 usa `assets/vendor/mp4-muxer.js`; áudio do microfone usa AAC quando suportado.75- **Fallback de compatibilidade:** navegador sem WebCodecs/`MediaStreamTrackProcessor`/`OffscreenCanvas` cai no caminho antigo — `MediaRecorder` sobre um canvas fixo 1080x1920 alimentado por `requestVideoFrameCallback` (MP4/`avc1` 12 Mbps, ou WebM com aviso). Só roda quando não há o pipeline em Worker.76- **Métricas reais ao vivo:** durante a gravação o painel mostra `fps efetivo · % descartado · fila do encoder · Mbps real · MB` (reportado pelo Worker). É o diagnóstico honesto — se o % descartado sobe ou o fps cai de 20, é o sinal para trocar para o modo Desempenho ou checar `chrome://gpu`. Abaixo de ~20 fps por 3s o painel também avisa uma vez (trecho de tela estática não conta como lentidão). Em notebook, grave na tomada.77- **Diagnóstico de recorte e navegação:** o painel registra `input`, `crop`, `output`, caminho `direct/canvas`, maior long task, gap de rAF e gap PTS na janela de cada `mira-navigation`. Ao finalizar, o botão **salvar diagnóstico JSON** permite anexar as métricas à evidência. Os limites Windows são long task ≤50 ms e gap PTS ≤100 ms na troca.78- **Qualidade × Desempenho:** seletor no painel. **Alta** = 1080×1920 (padrão de reels). **Desempenho** = grava na resolução NATIVA da coluna (~608×1080 num display comum), ~3× menos pixels a codificar — a alavanca real para máquina fraca, independente de CPU/GPU. Resolução constante mantém o MP4 `avc1` válido; o bitrate é escalado proporcionalmente.79- **Gravação longa — direto no disco, sem teto (padrão):** a chave **`salvar direto no disco`** (ligada por padrão) faz o Worker escrever o MP4 **no arquivo enquanto grava** (File System Access + `FileSystemWritableFileStreamTarget` do mp4-muxer, com `fastStart: false`). Nada acumula em RAM: a gravação dura o que o disco aguentar, e o `finalize()` deixa de copiar centenas de MB. O usuário escolhe o arquivo **uma vez, antes de começar** (o `showSaveFilePicker` exige ativação do usuário, por isso vem antes do seletor de captura); ao parar, o arquivo já está lá — não há download. **Preço honesto:** sem o buffer inteiro em mãos, o índice do MP4 (`moov`) vai para o **fim** do arquivo. Parar normalmente escreve o índice e o vídeo abre em qualquer player; um travamento do navegador no meio deixa um MP4 com os dados e **sem índice** (ilegível sem reparo). Se o seletor for cancelado, a gravação nem começa (e o arquivo de 0 byte é removido).80- **Gravação em memória (fallback):** sem File System Access (`file://`, outros navegadores) a chave fica desligada e cinza, e o mux volta a ser in-memory — com o teto real do `ArrayBuffer` (~2 GB): avisa por volta de ~384 MB e PARA sozinha perto de ~512 MB, que a 12 Mbps são uns **6 minutos**. Nesse modo, para clipes longos, grave em partes.81- **Microfone opcional:** toggle no painel, mixado na gravação (a câmera já está composta no slide).82- **Controles:** botão Gravar/Parar no painel ou tecla **R** (quieta nos modos E/P e digitação). Ao iniciar, o usuário escolhe "Esta guia" no seletor do navegador. O arquivo baixa sozinho ao parar (`mira-reels-<timestamp>.mp4`, ou `-PARCIAL` quando houve perda no caminho de encode/leitura/flush).83- **Recorte da coluna:** tenta **Element Capture** (`restrictTo` na seção visível) quando o deck declara `window.__miraElemCapture`; a track já sai 9:16 e o teleprompter fica fora do vídeo. O `restrictTo` é **reaplicado a cada troca de slide** (evento `mira-navigation` e `scroll`), senão o vídeo congela no slide anterior. Sem a flag ou sem suporte, cai no **Region Capture** de sempre.84- O painel some em telas estreitas (a coluna ocupa tudo) e nunca aparece na gravação.8586O OBS continua como alternativa (captura de janela + recorte); a gravação nativa é o caminho sem instalação.8788## Teleprompter que não entra no vídeo (padrão de todo deck mira-studio)8990Todo deck nasce com o teleprompter em **duas peças**, mais o editor de overlays e a persistência no arquivo. Os blocos canônicos estão no deck de referência; copie-os como estão.9192- **Painel lateral (`#mira-prompter`, tecla T):** fica na margem cinza, FORA da coluna. É o **editor**: as quatro chaves, o texto do slide (`#mp-body`, `contenteditable`) e o botão "Salvar no arquivo". **Some durante a gravação** (`html[data-mira-recording] #mira-prompter { display: none }`) — quem se lê no ar é o overlay.93- **Overlay central (`#tp-ov`, tecla O):** o retângulo que o apresentador lê, por cima da coluna (fundo preto 60%, texto branco 60%). É **irmão das `<section>`, nunca filho** — é exatamente isso que permite excluí-lo do vídeo.94- **Texto por slide:** vem do **`roteiro.md` na raiz do deck** (seção abaixo), não do HTML. Editar no painel reflete no overlay na hora, grava no `.md` e persiste em `localStorage['mira-tp-text']` (cópia de trabalho). O texto troca ao navegar (`scroll` + `mira-navigation`).95- **Element Capture (tecla G):** a gravação nativa restringe a captura à **subárvore da seção visível** (`RestrictionTarget.fromElement` + `track.restrictTo`), então tudo que não é descendente dela — o overlay e o painel — **não é pintado no vídeo**, mesmo sobreposto. O deck liga o recurso declarando `window.__miraElemCapture = true`; sem essa flag o `mira-record.js` usa o Region Capture de sempre.96- **Editor genérico de overlays (`.me-ov`, tecla E):** qualquer camada sobre a câmera marcada com `class="me-ov" data-me-chrome data-me-key="<id>"` (mais um filho `<div class="me-ov-grip" data-me-chrome></div>`) vira movível e redimensionável no modo E. O `data-me-chrome` é obrigatório: sem ele o `mira-edit-free` disputa o mesmo clique e seleciona o `<img>` interno em vez do grupo.97- **Salvar no arquivo (botão ou Ctrl+S):** grava o estado editável de LAYOUT (posições e tamanhos dos overlays, **sem o texto do roteiro**) no bloco `<script id="mira-studio-state" type="application/json">` do próprio `index.html` — em localhost por `POST /__mira_save`, em `file://` pela File System Access API. No load, um IIFE **semeia o `localStorage` a partir desse bloco**: o **arquivo é a fonte da verdade**, não o navegador. No template o bloco começa `{}`.9899**Onde cada overlay mora (a regra de ouro):** o que deve entrar no vídeo (logo, selo, animação sobre a câmera) fica **DENTRO** da `<section>`; o que não deve (teleprompter, painéis) fica **FORA** dela, como filho direto de `body`.100101### Restrições honestas (diga isto ao usuário, não prometa mais)102103- Excluir o teleprompter do vídeo só funciona no **gravador nativo (tecla R)**. **No OBS não**: ele grava os pixels da janela, e nada exclui um overlay. Para gravar no OBS, use só o painel lateral (que já fica fora da coluna recortada).104- Element Capture exige **Chrome/Edge desktop recente** e **contexto seguro** (localhost ou https). Sem suporte, o deck cai no Region Capture e o **overlay some durante a gravação** (fallback no CSS, via `html[data-mira-recording]:not([data-mira-elemcapture])`), para não vazar.105- `body > section { isolation: isolate }` é **pré-requisito**: sem stacking context o Chrome aceita o `restrictTo` e não emite frame — o MP4 sai vazio.106- Salvar por localhost exige o **servidor com os endpoints** (`/__mira_save`, `/__mira_meta`): num deck antigo, **reinicie o launcher** depois de atualizar o `mira-studio-server.cjs`.107108## Roteiro externo `roteiro.md` (todo deck de gravação nasce com um)109110O roteiro NÃO mora mais dentro do HTML. Todo deck gerado leva um **`roteiro.md` na raiz**, ao lado do `index.html`: é dele que saem os slides (layout e título) e a fala de cada slide. O apresentador escreve o roteiro no editor de texto que quiser, versiona em git, e vê o resultado no deck aberto sem recarregar.111112**Gramática (uma linha por cabeçalho):**113114```115<intro: texto livre, documenta a gramática para o usuário>116117## Slide 1 | capa | Um roteiro, *três formatos*118119Fala do apresentador neste slide.120121## Slide 2 | camera122123Fala do apresentador neste slide.124```125126- `layout` (obrigatório): `capa`, `camera`, `split` ou `full`, comparado em minúsculas. Valor desconhecido cai em `camera`, o layout mais simples.127- `Título`: vale em `capa`, `split` e `full`; ignorado em `camera`. `*entre asteriscos*` vira `<span class="accent">`, montado por fragmento (**nunca `innerHTML`**).128- **Sem campo de animação.** As animações do mira-studio são AUTORAIS (metáfora escrita à mão por slide, não montada a partir de uma lista de itens). O builder cria só o palco vazio `svg#sv-slide-N`, com **N = posição do slide no arquivo**, e cada animação escrita à mão se prende ao seu palco. Palco sem animação fica vazio em vez de quebrar; avise o usuário quando o roteiro tiver mais slides do que animações autoradas.129- O número do cabeçalho é **rótulo, não índice**, e continua sendo. Numeração duplicada ou fora de ordem não desloca texto nenhum.130- **Quem casa bloco com slide é a identidade, não a ordem.** Cada bloco leva `<!-- mira-slide-id: X -->` na linha abaixo do cabeçalho e a `<section>` correspondente leva `data-mira-slide-id="X"`. Com isso, reordenar os blocos no editor, reordenar os slides no modo E, ou os dois, dá o mesmo resultado: o slide anda inteiro, com palco, título e fala. Faltando id de um dos lados, cai no casamento por ordem de aparição de antes (deck antigo não precisa de migração). Detalhes em `_reversa_sdd/addenda/roteiro-identidade-de-slide-v001.md`.131- O `mira-slide-id` é **metadado, não fala**: o parser o extrai e o mantém fora do teleprompter e do overlay lido em câmera, e a escrita de volta o reemite verbatim.132133**O que sincroniza e o que não:**134135| Dado | Fonte da verdade | Quando vale |136|------|------------------|-------------|137| Layout, título | `roteiro.md` | lido uma vez, no **load** (mudou, recarregue) |138| Texto da fala | `roteiro.md` | **ao vivo**, nos dois sentidos |139| Posição/tamanho dos overlays | bloco `#mira-studio-state` no `index.html` | Ctrl+S |140| Cópia de trabalho do texto | `localStorage` | entre polls |141142Precedência no load: `roteiro.md` > `localStorage` > array `SCRIPT[]` embutido. O texto **não** entra no `#mira-studio-state`: duas fontes da verdade fariam o seed do load restaurar texto velho por cima do arquivo.143144**Como o deck consome (blocos canônicos no deck de referência):**145146- Um IIFE **antes** das animações e dos `<script defer>` faz a leitura **síncrona** do `.md` (os módulos de câmera, gravação e edição precisam das `<section>` já no DOM), guarda texto bruto, intro e cabeçalhos, monta as seções e as insere antes do painel do teleprompter, removendo as estáticas.147- As `<section>` estáticas do HTML continuam lá como **fallback**: em `file://`, sem servidor ou com parse vazio, elas SÃO o deck. A ausência do roteiro nunca produz deck em branco.148- Sincronização: poll de leitura a cada **1,5 s**, escrita com debounce de **800 ms**, com quatro guards que não são opcionais: (1) escrita em voo ou agendada trava o poll, senão ele desfaz o que você acabou de digitar; (2) gravação em andamento trava o poll, para não piscar texto dentro do vídeo; (3) campo com foco recebe estado e overlay mas não é sobrescrito, senão o cursor salta; (4) conteúdo idêntico aborta poll e escrita.149- A escrita de volta remonta o arquivo com a **intro e os cabeçalhos capturados no load** mais os textos atuais. Cabeçalho nunca é reescrito a partir do estado do deck.150- Arquivo ausente (404) é **recriado uma vez** a partir dos slides e textos embutidos.151152**Restrição honesta:** a escrita depende do `POST /__mira_save`. Ele existe no `mira/mira-studio-server.cjs` (launcher, que também cria o arquivo quando falta) e no `lib/mira-serve.js` (grava, mas só em arquivo que já existe). Em `file://` não há leitura nem escrita: o deck usa os slides embutidos, sem erro no console e sem sincronizar.153154**Chrome autoral dentro da `<section>`** (logo, selo, `.me-ov` que deve entrar no vídeo) precisa ser emitido pelo builder, senão a reconstrução do load o descarta.155156## Launcher `mira-studio-windows.bat` + `mira/mira-studio-server.cjs` (GPU dedicada, opcional)157158Fontes canônicas em `templates/studio/`: o `.bat` vai para a RAIZ do deck (diretiva: raiz = `index.html` + launchers) e o `mira-studio-server.cjs` para a pasta `mira/`. O ciclo de vida segue o padrão comprovado do Mira Remote/mesa tática: Node em primeiro plano, navegador aberto pelo servidor somente depois de `listen()` confirmar readiness.1591601. Sobe `mira/mira-studio-server.cjs` (Node puro): serve o deck em `http://127.0.0.1:8123` (ou próxima porta livre), expõe `/__mira/health` e `/__mira/gpus`. A consulta Win32 é uma Promise cacheada com estado `loading/ready/error`; o painel usa retry limitado. Falha de GPU não torna o HTTP do deck indisponível. O servidor também expõe **`GET /__mira_meta`** (caminho absoluto do alvo, usado pelo rótulo do mira-edit) e **`POST /__mira_save`** (grava o HTML no disco: é o "Salvar no arquivo" do deck e o Salvar da barra do mira-edit). O `/__mira_save` só aceita `.html`/`.htm`/`.md` (o `.md` é a escrita do `roteiro.md` pelo teleprompter), só dentro do root servido (trava de path traversal) e até ~25 MB. O MIME inclui `.md` e `.pdf` (slide `full` com PDF em `<iframe>` fica em branco sem ele).1612. Só depois do `listen()` bem-sucedido, o próprio servidor abre um Chrome dedicado (`--user-data-dir` em `%LOCALAPPDATA%\mira-studio\`) com `--force-high-performance-gpu`. A flag é uma **preferência**, não garantia: Windows/driver escolhem o adaptador final e o painel separa GPUs instaladas, renderer ativo e encoder hardware preferido. **Nenhuma escrita em registro ou configuração do Windows.**1623. O Node permanece em primeiro plano até `Ctrl+C`. Não use `start /wait chrome.exe` nem mate o servidor quando o comando Chrome retornar: se o mesmo perfil já estiver aberto, o Chrome encaminha a URL ao processo existente e retorna imediatamente.1634. stdout/stderr ficam visíveis e os eventos do servidor também são anexados a `mira/mira-studio.log`. Node ausente, portas esgotadas ou servidor ausente deixam mensagem acionável; não abra uma aba destinada a loading.164165Sem GPU dedicada o launcher é inócuo (a flag aponta para a única GPU); o deck continua funcionando por `index.html`/serve normal.166167## Bloco `<style id="mira-formato-multi">` canônico (gerar exatamente isto)168169```html170<style id="mira-formato-multi">171 /* Coluna 9:16 cravada, generalista para a tela (saída OBS 1080x1920). */172 :root {173 --fmt-w: calc(100vh * 9 / 16); --fmt-h: 100vh;174 /* Áreas seguras de plataforma (Reels + Shorts), % da largura da coluna. */175 --sz-top: 27.78%; /* 300/1080 — nav do Shorts / cabeçalho do Reels */176 --sz-right: 11.11%; /* 120/1080 — coluna de ações */177 --sz-bottom: 40.74%; /* 440/1080 — legenda, handle, ticker de áudio */178 --sz-left: 5.56%; /* 60/1080 — margem */179 }180 html { background: #000000; }181 body { background: #000000; display: flex; flex-direction: column; align-items: center; }182 body > section {183 position: relative;184 width: var(--fmt-w); height: var(--fmt-h); min-height: var(--fmt-h);185 overflow: hidden; background: var(--mira-bg, #0d0d0f);186 display: flex; flex-direction: column;187 /* stacking context: EXIGIDO pelo Element Capture. Sem isto o Chrome aceita188 o restrictTo e NÃO emite frame nenhum (o MP4 sai vazio). Não remova. */189 isolation: isolate;190 }191 /* camera: webcam na coluna inteira */192 section[data-layout="camera"] .cam-area { flex: 1 1 auto; min-height: 0; }193 /* split: quadrado 1:1 no topo + câmera intocada no resto */194 section[data-layout="split"] .split-top {195 width: 100%; aspect-ratio: 1 / 1; flex: 0 0 auto;196 display: flex; flex-direction: column;197 padding: var(--sz-top) var(--sz-right) 4.63% var(--sz-left);198 }199 section[data-layout="split"] .split-top h2 { flex: 0 0 auto; }200 section[data-layout="split"] .cam-area { flex: 1 1 auto; min-height: 0; }201 /* full: animação vertical na coluna inteira */202 section[data-layout="full"] .full-wrap {203 flex: 1 1 auto; min-height: 0;204 display: flex; flex-direction: column;205 padding: var(--sz-top) var(--sz-right) var(--sz-bottom) var(--sz-left);206 }207 section[data-layout="full"] h2 { flex: 0 0 auto; }208 /* palco: preenche todo o resto (viewBox casado em runtime pelo casarPalco) */209 .anim-stage { flex: 1 1 auto; min-height: 0; width: 100%; }210 .anim-stage svg { width: 100%; height: 100%; display: block; }211</style>212```213214Injete também o IIFE `fitTitles` (auto-ajuste de título para máx. 2 linhas) e a navegação por teclado quieta durante E/P (ambos no deck de referência).215216## Transição padrão: dissolve fora da gravação217218Todo deck mira-studio nasce com a transição **dissolve** (View Transitions same-document, o mesmo padrão do `mira-transition-dissolve`) aplicada DIRETO no `index.html`, sem arquivo `-dissolve` separado:219220- Bloco CSS marcado `=== DISSOLVE`: `::view-transition-old(root), ::view-transition-new(root) { animation-duration: 0.55s; }` e um `view-transition-name` único para CADA elemento de UI fixa (`#mrc-panel`, `.cam-notice` e qualquer outro `position: fixed`), senão a UI pisca no crossfade.221- Na navegação, helper `dissolve(jump)` com fallback (`if (document.startViewTransition) ... else jump()`) e `scrollIntoView({ behavior: 'instant' })`, nunca `'smooth'` ou `'auto'` dentro da transição.222- **Durante a gravação nativa**, `mira-record.js` marca `<html data-mira-recording="true">`; nesse estado a navegação chama `jump()` diretamente, sem `startViewTransition`. Antes do salto, emita `window.dispatchEvent(new CustomEvent('mira-navigation', {detail:{from,to,at:performance.now()}}))` para abrir a janela de métricas. Os snapshots old/new disputam a captura da própria guia e podem criar hitch/gap no MP4. Ao terminar, o atributo é removido e o dissolve volta automaticamente.223224Os dois blocos estão no deck de referência; detalhes e regras completas em `agents/mira-transition-dissolve/SKILL.md`.225226## Teclas do deck (documente na entrega)227228**T** painel lateral · **O** overlay central · **G** Element Capture · **E** editar (mover/redimensionar overlays) · **Ctrl+S** salvar no arquivo · **R** gravar · **C** espelhar câmera · **P** pintar · setas navegam. T/O/G ficam quietas nos modos E/P e durante a digitação.229230## Passos2312321. **Criar toda a estrutura — primeira ação obrigatória.** Antes de perguntar pelo roteiro, ler referências, escolher layouts ou gerar qualquer arquivo, derive o slug do pedido (ou use `novo-deck-studio`, com sufixo anticolisão), resolva `deck_id = YYYY-MM-DD <slug>` e crie `decks/<deck_id>/`, `references/`, `assets/`, `assets/vendor/` e `mira/`. Informe o caminho absoluto de `references/`. Nenhuma outra ação pode vir antes desta.2332. **Colher o roteiro.** Liste com o usuário os slides e o layout de cada um. Sem layout declarado, pergunte. O que ele vai FALAR em cada slide vai para o **`roteiro.md`**, não para dentro do HTML. Diga a ele, em uma linha, que dá para editar esse arquivo com o deck aberto: o texto aparece no teleprompter em cerca de 1,5 s.234 Depois, complete a estrutura com `index.html`, **`roteiro.md`**, módulos em `mira/`, vendor em `assets/vendor/` e `mira-studio-windows.bat` na raiz. As pastas já existentes são reutilizadas, nunca recriadas nem abandonadas.2353. **Gerar os slides.** Um bloco `## Slide` no `roteiro.md` por slide e, no HTML, o `body > section` equivalente (fallback de `file://`) com `data-layout` correto; `.cam-area` nas áreas de câmera; animações nativas da geometria (quadrado no `split`, retrato no `full`) com `casarPalco` + enquadramento **uma vez** sobre a parte estática (reenquadrar a cada frame faz o palco reescalar junto com o que se move) e loop interno. Todo callback de `d3.timer` vai dentro de `try/catch`: uma exceção num deles congela a FILA inteira de timers do d3.2364. **Injetar os blocos canônicos.** `<style id="mira-formato-multi">` (com o `isolation: isolate`), o **builder do `roteiro.md`** (antes das animações e dos `<script defer>`), `fitTitles`, navegação com dissolve (transição padrão), o **teleprompter completo** (painel + overlay + sincronização com o `.md` + `SCRIPT[]` só como fallback + chaves + editor `.me-ov` + bloco `#mira-studio-state` vazio + seed + salvar/Ctrl+S) e os cinco `<script defer src="mira/...">` antes de `</body>` (`mira-edit.js` → `mira-edit-free.js` → `mira-draw.js` → `mira-camera.js` → `mira-record.js`).2375. **Verificar.** Servido em localhost: câmera nas áreas certas, permissão pedida uma vez, animações preenchendo, títulos em máx. 2 linhas. Painel lateral com as chaves T/O/G/E sincronizadas; editar o texto reflete no overlay; editar o `roteiro.md` no editor externo aparece no deck em ~1,5 s e digitar no painel grava no `.md` sem tocar na intro nem nos cabeçalhos; **Ctrl+S** grava posições e tamanhos, que sobrevivem ao reload. Gravando com `Element Capture: ON`, o overlay continua visível para você e **some do MP4** — e navegar entre slides durante a gravação não pode congelar o vídeo. Em `file://`: áreas verdes `#00FF00` puras.2386. **Reportar.** Caminho do deck, o `roteiro.md` como lugar de escrever a fala (editável com o deck aberto), layout de cada slide (uma linha por slide), a gravação nativa (tecla R; encoder Auto/Hardware preferido/Software no painel; launcher Windows para inventário e preferência de alto desempenho) e a receita OBS como alternativa: servir com `node lib/mira-serve.js "decks/<deck_id>"` (ou `npx mira-animator serve`), Chrome em tela cheia, Captura de Janela no OBS, recorte na coluna, gravação 1080x1920.239240## Edge cases (do mais comum ao menos)241242- **Aberto em `file://`:** `getUserMedia` não existe; todas as áreas de câmera ficam verde chroma e o aviso ensina a servir em localhost. O deck continua navegável e gravável (keying manual).243- **Permissão negada / sem webcam:** mesmo fallback verde; aviso específico.244- **Webcam 16:9 numa área 9:16 ou quadrada:** `object-fit: cover` corta as sobras, nunca distorce.245- **Título longo no `split`/`full`:** `fitTitles` reduz até 2 linhas; o `casarPalco` re-casa o palco à altura restante.246- **Vários slides com câmera:** todos compartilham o MESMO stream; trocar de slide não repete o prompt.247- **Tecla C durante edição (modo E) ou digitação:** o módulo ignora, sem conflito.248- **Deck sem nenhuma `.cam-area`:** o módulo fica inerte (não pede permissão à toa).249250## Checklist251252**Os que mais falham (cheque primeiro):**253- [ ] Cada slide com o `data-layout` que o usuário pediu, na ordem do roteiro.254- [ ] `split`: contêiner 1:1 exato, caixa informativa 900 × 730, palco elástico e câmera com a mesma altura do baseline.255- [ ] `full`: caixa informativa 900 × 1180, animação vertical preenchendo o palco seguro.256- [ ] Câmera: stream único, mudo, espelhado por padrão, tecla C alternando.257- [ ] Fallback: em `file://` as áreas ficam `#00FF00` PURO, sem texto por cima.258259**Teleprompter (o que mais quebra aqui):**260- [ ] `body > section { isolation: isolate }` presente (sem ele o Element Capture grava vídeo VAZIO).261- [ ] Painel `#mira-prompter` e overlay `#tp-ov-wrap` **fora** das `<section>`; overlays que devem entrar no vídeo, **dentro**.262- [ ] `roteiro.md` na raiz, com intro documentando a gramática e um `## Slide` por `<section>`; os layouts citados na intro batem com os que o deck aceita.263- [ ] Slides nascem do `.md`; sem o arquivo (ou em `file://`), o deck sobe com os slides padrão embutidos, sem erro no console.264- [ ] Numeração duplicada ou fora de ordem nos cabeçalhos não desloca os textos.265- [ ] Cada `<section>` tem `data-mira-slide-id`, pareado com o `<!-- mira-slide-id -->` do bloco correspondente.266- [ ] Trocar dois blocos de lugar no `roteiro.md` e recarregar leva palco, título e fala juntos; nenhum palco `<slug>-stage` vira `sv-slide-N`.267- [ ] O `<!-- mira-slide-id -->` não aparece no painel do teleprompter nem no overlay.268- [ ] Editar o `.md` aparece no deck em ~1,5 s; digitar no painel grava no `.md` com intro e cabeçalhos intactos; digitação contínua não tem o cursor roubado pelo poll.269- [ ] Durante a gravação o poll fica parado; `.md` apagado com o deck aberto é recriado.270- [ ] Builder do roteiro ANTES das animações e dos `<script defer>`; animação autoral presa ao palco `sv-slide-N`.271- [ ] `SCRIPT[]` continua no HTML só como fallback, e `mira-tp-text` NÃO entra no `#mira-studio-state`.272- [ ] `window.__miraElemCapture = true` declarado (é o opt-in que liga o Element Capture no mira-record).273- [ ] `mira/mira-record.js` é a cópia ATUAL de `templates/authoring/` (tem a chave "CFR (edição)" no painel). Deck antigo sem ela grava VFR e dessincroniza no Premiere.274- [ ] Bloco `#mira-studio-state` começa `{}`, com o IIFE de **seed antes** de qualquer leitor de `localStorage`.275- [ ] `.me-ov` com `data-me-chrome` (senão o mira-edit-free briga pelo clique) e `.me-ov-grip`.276- [ ] Restrições honestas ditas ao usuário: só no gravador nativo (R), não no OBS; Chrome desktop recente; localhost/https.277278- [ ] Transição dissolve aplicada no `index.html` (bloco `=== DISSOLVE` + `dissolve()` na navegação; UI fixa com `view-transition-name`, inclusive `#mira-prompter` e `#tp-ov-wrap`).279- [ ] Durante recording, navegação instantânea sem `startViewTransition` e evento `mira-navigation` emitido antes do salto.280- [ ] Coluna `calc(100vh * 9/16)` x `100vh`, laterais `#000000`, centralizada via flex.281- [ ] `mira/` com os 5 módulos e tags na ordem certa antes de `</body>`.282- [ ] `assets/vendor/mp4-muxer.js` presente (encoders do painel), `mira-studio-windows.bat` na raiz e `mira/mira-studio-server.cjs` (launcher + inventário real de GPUs).283- [ ] Painel separa inventário de GPUs, renderer ativo e preferência do encoder; diagnóstico JSON disponível ao final.284- [ ] Loop interno em toda animação; generation counter presente.285- [ ] Nenhum texto abaixo de 13px renderizados; título máx. 2 linhas.286- [ ] Capa (se houver) com `text-wrap: balance`; sem travessão em texto visível.287- [ ] Receita OBS reportada ao final.
Run npx skillmds@latest add sandeco/mira-studio in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
Gera um deck VERTICAL 9:16 (1080x1920) pronto para gravar no OBS Studio, onde cada slide declara um de três layouts: camera (webcam ao vivo em tela cheia), split (animação quadrada estilo mira-squared em cima + câmera embaixo) e full (animação vertical estilo mira-vertical). A câmera do apresentador é embutida ao vivo no slide via getUserMedia (módulo mira/mira-camera.js), sem chroma key: no OBS basta capturar a janela. Sem câmera, a área vira verde chroma #00FF00 como plano B. Use SEMPRE que o usuário disser /mira-studio, deck para OBS, deck com câmera, slide com câmera, meio a meio, câmera embutida, deck para gravar vídeo comigo falando, ou pedir slides que misturam câmera e animação num vídeo vertical. It is listed under Docs & Writing on SkillMD.
This skill has not completed SkillMD's automated safety review yet. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
sandeco (@sandeco) published this skill. Their other Agent Skills are listed on their SkillMD profile.