- name
- mira-studio-full
- description
- Gera um deck HORIZONTAL 16:9 (1920x1080, arquivo index-16x9.html) pronto para gravar videoaula sem OBS, onde cada slide declara um de três layouts: camera (webcam ao vivo em tela cheia), thirds (animação nos dois terços da esquerda + câmera ao vivo no terço direito) e full (animação em tela cheia, sem câmera). Os slides nascem do roteiro.md (layout, título e animação declarativa linha/orbita por cabeçalho), o teleprompter em overlay fica fora do vídeo via Element Capture e a gravação nativa sai em MP4 full-hd pela tecla R, com painel de encoder, câmera, microfone e gravação direta no disco. Use SEMPRE que o usuário disser /mira-studio-full, deck 16:9 com câmera, videoaula com câmera embutida, studio horizontal, gravar aula em full hd, terços com câmera, ou pedir slides horizontais que misturam câmera e animação num vídeo 16:9. Para vídeo VERTICAL 9:16 (Reels, Shorts, TikTok), use /mira-studio.
# Skill: Mira Studio Full (16:9 com câmera embutida, gravação nativa)
## 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 horizontais 16:9 full-hd para gravação de videoaula em que o apresentador aparece AO VIVO dentro do próprio slide. Cada slide declara um layout no `roteiro.md`:
- **`camera`** — a webcam preenche o quadro inteiro (você falando).
- **`thirds`** — título + animação declarativa nos 2/3 da esquerda e a câmera ao vivo no 1/3 direito (separados por uma linha sutil).
- **`full`** — título + animação no quadro inteiro, sem câmera (a fala fica em off, lida no teleprompter).
> **Fonte da verdade:** o padrão desta skill está congelado no deck de referência. Resolva o arquivo nesta ordem:
> 1. `mira-templates/decks/mira-studio-full-demo/index-16x9.html` (projeto com Mira instalado)
> 2. `templates/decks/mira-studio-full-demo/index-16x9.html` (repositório fonte do Mira)
> 3. `node_modules/mira-animator/templates/decks/mira-studio-full-demo/index-16x9.html`
>
> 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
Um quadro 16:9 cravado à janela (letterbox `#000000` quando a tela não é 16:9) chamado `index-16x9.html`, onde cada `body > section` declara `data-layout="camera|thirds|full"`, os slides NASCEM do `roteiro.md` (layout, título e animação `linha:`/`orbita:` por cabeçalho; texto da fala sincronizando ao vivo), a webcam entra ao vivo pelas `.cam-area` (`mira/mira-camera.js`), o teleprompter em overlay fica FORA do vídeo via Element Capture, e a tecla **R** grava um MP4 1920x1080 direto no disco pelo `mira/mira-record-16x9.js`, sem OBS.
## Diferenças para o /mira-studio (não confunda)
| | `/mira-studio` | `/mira-studio-full` |
|---|---|---|
| Formato | 9:16 vertical (coluna) | 16:9 horizontal (quadro cobre a janela) |
| Arquivo | `index.html` | `index-16x9.html` |
| Layouts | `capa`, `camera`, `split`, `full` | `camera`, `thirds`, `full` |
| Animações | autorais (escritas à mão por slide) | declarativas no roteiro (`linha:` / `orbita:`), autoral opcional |
| Gravador | `mira-record.js` (1080x1920) | `mira-record-16x9.js` (1920x1080) |
| Painel de gravação | na margem, fora da coluna | SOBRE o slide (some do vídeo via Element Capture) |
| Launcher | `mira-studio-windows.bat` | `mira-studio-16x9-windows.bat` / `-apple.command` |
Pedido de vertical/Reels/Shorts dentro desta skill: aponte para `/mira-studio`.
## Dimensão (o bloco de formato canônico)
O quadro é 16:9 cravado e generalista para a tela: `--fmt-w: min(100vw, calc(100vh * 16 / 9))` e `--fmt-h: min(100vh, calc(100vw * 9 / 16))`. Em tela cheia num display 1080p fecha exatos 1920x1080; em janela menor encolhe mantendo a proporção. Regras que acompanham (todas no deck de referência):
- `body > section` com `margin: calc((100vh - var(--fmt-h)) / 2) 0` e `scroll-margin-top` igual: a sobra vertical vira faixa `#000` acima e abaixo, nunca o slide seguinte.
- `html` com `scroll-snap-type: y proximity`, `scrollbar-width: none` e `overflow-x: hidden`: a barra de rolagem roubava largura e criava scroll horizontal em F11. Navegação por teclado ou roda do mouse.
- `body > section { isolation: isolate }` é PRÉ-REQUISITO do Element Capture: sem stacking context o Chrome aceita o `restrictTo` e não emite frame nenhum (o MP4 sai vazio).
- `thirds`: `.thirds-main` com `width: 66.667%`, `padding: 50px` (área segura onde título e animação vivem), `h2` centrado no topo; `.cam-area` com `width: 33.333%` e `border-left: 1px solid var(--line)`.
- `full`: `.full-main` ocupando o quadro inteiro (`padding: 50px`, mesma área segura), `h2` centrado no topo, SEM `.cam-area` (o builder não a cria neste layout).
- Tema mira-dark embutido nas variáveis `--mira-*` (deck self-contained); destaque `#FF904D`.
- Primeiro slide com `h1/h2`: `text-wrap: balance` (diretiva do título da capa).
## Roteiro externo `roteiro.md` (os slides nascem dele)
Todo deck gerado leva um **`roteiro.md` na raiz**: é dele que saem os slides E as animações. O usuário escreve no editor que quiser e vê o resultado no deck aberto.
**Gramática (uma linha por cabeçalho):**
```
## Slide N | layout | Título | animação
```
- `layout` (obrigatório): `camera`, `thirds` ou `full`, comparado em minúsculas. Valor desconhecido cai em `camera`.
- `Título` (thirds/full): `*entre asteriscos*` vira `<span class="accent">`, montado por fragmento (**nunca `innerHTML`**).
- `animação` (thirds/full): **`linha: A, B, C, D`** (etapas em diagonal, orbe percorrendo e acendendo cada nó com pulso) ou **`orbita: A, B, C @ NÚCLEO`** (satélites girando em elipse em torno do núcleo). Sem o campo ou valor inválido, cai em `linha` padrão.
- O número do cabeçalho é **rótulo, não índice**, e continua sendo.
- **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"`. Reordenar os blocos no editor ou os slides no modo E 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**: fica fora do teleprompter e do overlay lido em câmera.
- O texto abaixo do cabeçalho é a fala do slide (teleprompter e overlay).
**O que sincroniza e o que não:**
| Dado | Fonte da verdade | Quando vale |
|------|------------------|-------------|
| Layout, título, animação | `roteiro.md` | lido uma vez, no **load** (mudou, recarregue) |
| Texto da fala | `roteiro.md` | **ao vivo**, nos dois sentidos |
| Posição/tamanho/fonte do overlay + textos | bloco `#mira-studio-state` no `index-16x9.html` | Ctrl+S |
| Cópia de trabalho | `localStorage` | entre polls |
- Builder **síncrono antes** das animações e dos `<script defer>` (os módulos leem as `<section>` logo em seguida): busca o `.md`, guarda texto bruto, intro e cabeçalhos, remonta as seções antes do painel do teleprompter. As `<section>` estáticas do HTML ficam como fallback: em `file://` ou sem o arquivo, elas SÃO o deck.
- Sincronização: poll de leitura a cada **1,5 s**, escrita com debounce de **800 ms**. Guards obrigatórios: escrita em voo trava o poll; gravação em andamento trava o poll; campo com foco não é sobrescrito; conteúdo idêntico aborta.
- 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.
- **Estado no arquivo:** diferente do 9:16, aqui o `#mira-studio-state` guarda **texto (`mira-tp-text`) E layout do overlay (`mira-tp-ov-pos`)**. O seed no load é **guardado por hash**: só sobrescreve o `localStorage` quando o bloco MUDOU desde o último seed, então ajustes locais ainda não salvos sobrevivem a um recarregar, e um arquivo atualizado sempre vence.
## As animações declarativas (animLinha e animOrbita)
Os dois geradores estão no deck de referência; copie-os como estão. Regras que carregam:
- **Regra Zero:** entrada coreografada (haste se desenha e nós pipocam; núcleo cresce e satélites acendem) e DEPOIS o loop perpétuo via `d3.timer`, com generation counter (`window.__animGen[svgId]`): cada rebuild mata o timer anterior no próximo tick.
- **Fora da tela o loop morre:** `IntersectionObserver` (threshold 0.35) reconstrói ao entrar e invalida a geração ao sair. Trocar de slide não acumula timers.
- `casarPalco` (viewBox casado ao box real do palco) + `fitOnce` sobre a parte ESTÁTICA, uma vez (reenquadrar a cada frame faz o palco reescalar junto com o que se move).
- Todo callback de `d3.timer` dentro de `try/catch`: uma exceção congela a fila inteira de timers do d3.
- Texto SVG: `font-size >= 24` para `W = 960`; cor da marca `#FF904D` via variáveis do tema; sem arco-íris.
- Animação AUTORAL além das duas: permitida, presa ao palco `svg#sv-slide-N` (N = posição do slide no arquivo), seguindo as mesmas regras e o 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 preenchido com cenário ambiente da própria metáfora (parado ou em deriva lenta, nunca focal). As declarativas `linha`/`orbita` continuam como estão, mas devem preencher o palco. Palco sem animação fica vazio em vez de quebrar.
## Teleprompter que não entra no vídeo
Duas peças, mais o estado no arquivo. Blocos canônicos no deck de referência.
- **Painel lateral (`#mira-prompter`, tecla T):** o editor. Quatro chaves (T painel, O overlay, G Element Capture, E mover/redimensionar), slider de tamanho do texto do overlay por slide (padrão do deck: **34px**, caixa **621x454**), 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 }`).
- **Overlay central (`#tp-ov-wrap`/`#tp-ov`, tecla O):** o retângulo que o apresentador lê (fundo preto 60%, texto branco 60%), **irmão das `<section>`, nunca filho**: é isso que o exclui do vídeo no Element Capture.
- **Rolagem automática (teleprompter de verdade):** tecla **L** liga/pausa a rolagem do overlay (P é da caneta), **+ / -** ajustam a velocidade (10 a 200 px/s, persistida). Na troca de slide o texto volta ao topo e espera ~1 s antes de rolar. O degradê `.tp-ov-more` indica texto abaixo do corte; um toast discreto (`#tp-toast`) confirma liga/pausa e velocidade.
- **Modo E no overlay:** arrastar move; alça da borda direita muda largura, da borda de baixo muda altura, grip do canto muda as duas. Tudo por slide, persistido em `mira-tp-ov-pos`.
- **Element Capture (tecla G, LIGADO por padrão):** o deck declara `window.__miraElemCapture = true`; a gravação restringe a captura à subárvore da seção visível (`RestrictionTarget.fromElement` + `track.restrictTo`), então overlay, painel do teleprompter e painel de gravação **não são pintados no vídeo**, mesmo sobrepostos.
- **Cheat-sheet (tecla ?):** grade com todos os atalhos, fora do vídeo, Esc ou clique fecha.
- **Salvar (botão ou Ctrl+S):** grava textos e layout do overlay no bloco `<script id="mira-studio-state" type="application/json">` do próprio `index-16x9.html`: em localhost por `POST /__mira_save`, em `file://` pela File System Access API. O arquivo é a fonte da verdade, não o navegador.
**Onde cada overlay mora (regra de ouro):** o que deve entrar no vídeo (logo, selo, `.me-ov` com `data-me-chrome` + `data-me-key`) fica **DENTRO** da `<section>`; o que não deve (teleprompter, painéis) fica **FORA**, como filho direto de `body`.
## Desenho por slide (caneta P)
A caneta do `mira-draw.js` desenha sobre o slide ATUAL: ao trocar de slide os traços saem junto e voltam quando o slide volta (bloco canônico usando `miraDraw.getShapes/setShapes` por índice de slide). No palco do `mira-remote` o desenho é da shell (modelo global sincronizado): o bloco detecta `window.__MIRA_REMOTE_STAGE__` e não interfere.
## O módulo mira/mira-record-16x9.js (gravação nativa 1920x1080)
Fonte canônica em `templates/authoring/mira-record-16x9.js`; copie para `mira/` do deck. O que muda em relação ao gravador 9:16:
- **Painel SOBRE o slide:** no 16:9 o quadro cobre a janela, então o painel de gravação flutua sobre o slide (arrastável). Gravando **com** Element Capture ele continua visível para você e fora do MP4; gravando **sem** (Region Capture), ele é ocultado via CSS durante a gravação e a tecla R segue funcionando.
- **Contagem regressiva 3-2-1** antes de iniciar (fora do vídeo: aparece antes do pipeline).
- **Saída H.264 `avc1` com resolução constante por sessão:** **1920x1080** em Alta (padrão de videoaula) ou a resolução **16:9 nativa da janela** em Desempenho (menos pixels a codificar, a alavanca real para máquina fraca). Bitrate 12 Mbps escalado proporcionalmente; keyframe a cada 2 s.
- **Pipeline em Worker** idêntico ao padrão comprovado do 9:16: `MediaStreamTrackProcessor` puxa `VideoFrame`s da track restringida/recortada, o `readable` é transferido ao Worker (Blob URL, sem arquivo extra), `VideoEncoder` com backpressure (`encodeQueueSize>=2` descarta não-chave), áudio AAC no mesmo Worker, mux `mp4-muxer` com `firstTimestampBehavior: 'offset'` (por trilha — **nunca** `cross-track-offset`). O main thread só renderiza a página.
- **CFR (edição) — o MP4 entra no Premiere sem drift de áudio:** chave no painel, **ligada por padrão**, idêntica à do 9:16. O Worker põe cada frame num slot da grade de 1/FPS antes do encoder e preenche slot vazio com o quadro anterior (teto de 2 s). Sem isso a trilha sai VFR: VLC e Chrome tocam certo (honram PTS), mas o Premiere conforma VFR numa grade fixa e a boca desencontra da voz de forma PROGRESSIVA. Painel mostra `N dup` / `N salto`; o JSON traz `timing: {mode, dupFilled, dupDropped, gapJumped}`. Desligada, volta ao VFR de antes. **A grade CFR trata a deriva PROGRESSIVA e só ela.** O deslocamento CONSTANTE entre as trilhas é outro defeito (BUG-20260815-HYRG, corrigido em 2026-08-16): o vídeo chega ao muxer já rebaseado em zero pela grade e o áudio no relógio nativo, então `firstTimestampBehavior: 'offset'` zerava cada trilha na própria origem e jogava fora a distância entre elas. Hoje quem alinha é o gravador, em `mandaAoMux()`, e o desvio medido aparece no painel (`A/V ±N ms`) e no diagnóstico (`av: {firstVideoUs, firstAudioUs, deltaMs}`). Contrato no adendo `_reversa_sdd/addenda/bug-BUG-20260815-HYRG-v001.md`. Trocar a constante do muxer sem esse alinhamento reintroduz o commit `6e84363`.
- **Seletores de câmera e microfone no painel**, com medidor de nível (VU) do microfone. A troca de câmera é AO VIVO (`window.__miraCameraUse` do `mira-camera.js`), persiste em `mira-cam-device` e vale para os próximos loads.
- **Encoder Auto / Hardware preferido / Software (CPU)** (`hardwareAcceleration` é preferência, não garantia) e as três informações separadas: GPUs instaladas (`/__mira/gpus`, via launcher), renderer ativo (WebGL) e a preferência do encoder. GPUs instaladas nunca viram opções do encoder.
- **Gravação direta no disco** (File System Access + `FileSystemWritableFileStreamTarget`, `fastStart: false`): escolhe o arquivo uma vez antes de começar, nada acumula em RAM, sem teto de duração. Preço honesto: o índice `moov` vai para o fim; travamento no meio deixa MP4 sem índice. Fallback in-memory (~2 GB de teto, aviso ~384 MB, para sozinha ~512 MB) quando não há File System Access.
- **Métricas reais ao vivo** (fps efetivo, % descartado, fila do encoder, Mbps, MB) e **diagnóstico JSON** por `mira-navigation` (input/crop/output, long task, gap de rAF, gap PTS) com botão de salvar ao final.
- **Fallback de compatibilidade:** sem WebCodecs/`MediaStreamTrackProcessor`/`OffscreenCanvas`, cai no `MediaRecorder` sobre canvas fixo 1920x1080.
- **Tecla R** grava/para (quieta nos modos E/P e digitação). Ao iniciar, escolha "Esta guia" no seletor do navegador.
## Launcher `mira-studio-16x9-windows.bat` / `-apple.command` + `mira/mira-studio-server.cjs`
Fontes canônicas em `templates/studio/`: os launchers vão para a RAIZ do deck e o `mira-studio-server.cjs` para `mira/`. Mesmo ciclo de vida comprovado do Mira Remote: Node em primeiro plano, Chrome aberto pelo servidor somente depois de `listen()`.
- Os launchers 16:9 exportam **`MIRA_STUDIO_PAGE=/index-16x9.html`** (página inicial servida) e **`MIRA_STUDIO_FULLSCREEN=1`** (Chrome abre em `--start-fullscreen`: F11 já na abertura, para o quadro fechar 1920x1080 exato).
GitHub에서 보기