sagadeck 1.3.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +4 -4
  2. package/bin/sagadeck.js +9 -1
  3. package/docs/ANDAMENTO.md +376 -0
  4. package/docs/REFERENCIA.md +4 -4
  5. package/package.json +1 -1
  6. package/src/ai/bench.js +132 -0
  7. package/src/ai/context.js +12 -3
  8. package/src/ai/critique.js +114 -0
  9. package/src/ai/deck-ai.js +234 -30
  10. package/src/ai/document-materials.js +2 -2
  11. package/src/ai/document-visuals.js +400 -20
  12. package/src/ai/llm.js +19 -5
  13. package/src/ai/progress.js +23 -0
  14. package/src/ai/quality.js +60 -0
  15. package/src/api-client.js +2 -1
  16. package/src/build.js +5 -1
  17. package/src/decision-lab.js +2 -1
  18. package/src/deck-file.js +2 -1
  19. package/src/elements.js +44 -7
  20. package/src/figures/charts.js +7 -4
  21. package/src/figures/diagrams.js +15 -1
  22. package/src/figures/ufmap.js +2 -1
  23. package/src/fs-retry.js +19 -0
  24. package/src/import/crop.js +27 -8
  25. package/src/layouts.js +22 -2
  26. package/src/library.js +68 -16
  27. package/src/locale.js +18 -0
  28. package/src/mcp/server.js +2 -2
  29. package/src/motion.js +4 -2
  30. package/src/preferences.js +2 -1
  31. package/src/runtime/base.css +3 -0
  32. package/src/runtime/calc.js +3 -3
  33. package/src/runtime/decision-lab.js +1 -1
  34. package/src/runtime/fit.js +20 -1
  35. package/src/runtime/runtime.js +2 -1
  36. package/src/studio/ai-chat-route.js +119 -4
  37. package/src/studio/code-version.js +35 -0
  38. package/src/studio/generate.js +53 -0
  39. package/src/studio/project.js +8 -7
  40. package/src/studio/public/app.js +7 -216
  41. package/src/studio/public/chat.js +71 -1
  42. package/src/studio/public/header-footer.js +140 -0
  43. package/src/studio/public/index.html +5 -0
  44. package/src/studio/public/library.html +1 -0
  45. package/src/studio/public/library.js +4 -3
  46. package/src/studio/public/preferences-ui.js +83 -0
  47. package/src/studio/public/provenance.js +13 -0
  48. package/src/studio/public/style.css +17 -0
  49. package/src/studio/public/ui-icons.js +1 -1
  50. package/src/studio/public/update-notice.js +25 -0
  51. package/src/studio/public-files.js +11 -1
  52. package/src/studio/server.js +20 -29
  53. package/src/studio/share-routes.js +2 -1
package/README.md CHANGED
@@ -26,7 +26,7 @@ A IA funciona apontando para um modelrelay ou gateway compatível (`SAGADECK_LLM
26
26
 
27
27
  ## Como usar
28
28
 
29
- Toda apresentação mora na **biblioteca**: `SAGADECK_HOME`, ou `~/sagadeck` (no Windows, `C:Users<você>sagadeck`). Uma pasta por tópico, uma por apresentação.
29
+ Toda apresentação mora na **biblioteca**: `SAGADECK_HOME`, senão a pasta `sagadeck` dentro de **Documentos** no Windows (a pasta Documentos que o Explorer mostra, mesmo redirecionada para o OneDrive ou outro disco) e `~/sagadeck` no Mac e no Linux. Quem usava a biblioteca antiga em `C:\Users\<você>\sagadeck` tem ela movida para Documentos na primeira execução; o caminho antigo continua levando até lá. Uma pasta por tópico, uma por apresentação.
30
30
 
31
31
  ```bash
32
32
  sagadeck new "Minha palestra" --topic=Palestras --theme=editorial
@@ -74,7 +74,7 @@ Se o código de uma ferramenta em Python quiser chamar o sagadeck diretamente (s
74
74
  ```python
75
75
  import sagadeck
76
76
  sagadeck.autofix("palestra.yaml") # corrige sobreposições e margens automaticamente
77
- sagadeck.studio() # abre a biblioteca (~/sagadeck)
77
+ sagadeck.studio() # abre a biblioteca (Documentos/sagadeck no Windows)
78
78
  sagadeck.studio("palestra.yaml", port=3517) # abre direto o editor de um deck
79
79
  sagadeck.export("palestra.yaml", out="saida") # {'html': …, 'pptx': …, 'pdf': …, 'roteiro': …}
80
80
  print(sagadeck.check("palestra.yaml")) # relatório do fiscal em texto
@@ -193,7 +193,7 @@ formato avisa para atualizar o sagadeck. Se um filtro de e-mail barrar a extens
193
193
  ## Biblioteca
194
194
 
195
195
  `sagadeck studio` sem arquivo abre a biblioteca: suas apresentações organizadas em tópicos, com capa, busca,
196
- lixeira (30 dias) e o menu **⋯** de cada cartão (apresentar, renomear, duplicar, mover, baixar tudo/.sagadeck/PPTX/PDF).
196
+ lixeira (um dia) e o menu **⋯** de cada cartão (apresentar, renomear, duplicar, mover, baixar tudo/.sagadeck/PPTX/PDF).
197
197
 
198
198
  **Nova apresentação** tem três caminhos: *Descrever com IA* (o assunto, quanto tempo você tem, que vira o número de
199
199
  slides, o estilo e, se quiser, material de apoio: PDF, Word, PowerPoint, Excel ou um link), *A partir de um arquivo
@@ -205,7 +205,7 @@ Arraste um cartão para um tópico para movê-lo. O ícone da biblioteca, no can
205
205
  Não tem banco de dados: a biblioteca é uma pasta comum, que dá para abrir no Explorer e fazer backup.
206
206
 
207
207
  ```text
208
- ~/sagadeck/ (ou SAGADECK_HOME, ou --library=PASTA)
208
+ Documentos/sagadeck/ (Windows; ~/sagadeck no Mac/Linux; ou SAGADECK_HOME, ou --library=PASTA)
209
209
  Palestras/ tópico = pasta (a cor fica em .topico.json)
210
210
  Minha palestra/ apresentação = pasta com o YAML e os arquivos dela
211
211
  Minha palestra.yaml
package/bin/sagadeck.js CHANGED
@@ -57,7 +57,7 @@ const HELP = `sagadeck — YAML -> apresentação (HTML animado + PowerPoint edi
57
57
  sagadeck estudo <deck.yaml> [--html] gera <deck> - material de estudo.pdf (cada slide + texto de consulta)
58
58
  sagadeck all <deck.yaml> build + check + pptx + pdf + roteiro
59
59
  sagadeck studio [deck.yaml|x.sagadeck] [--port=3517] [--library=PASTA] sem arquivo: abre a biblioteca; já aberto: usa o aberto
60
- (PASTA padrão: SAGADECK_HOME ou ~/sagadeck); com arquivo: abre o editor dele
60
+ (PASTA padrão: SAGADECK_HOME, senão Documentossagadeck no Windows, ~/sagadeck fora dele); com arquivo: abre o editor dele
61
61
  --host=0.0.0.0 abre para a rede (padrão: só esta máquina)
62
62
  --multiuser: uma biblioteca por usuário, atrás de um proxy que envia X-Sagadeck-User
63
63
  --agentes=naru,ana: no multiusuário, quem pode deixar a IA rodar comandos (padrão: ninguém)
@@ -124,6 +124,14 @@ async function doShots(p, dir = p.shots) {
124
124
  }
125
125
 
126
126
  async function main() {
127
+ // biblioteca antiga (~/sagadeck) vai para Documentos\sagadeck no Windows, uma vez (src/library.js)
128
+ if (!flags.library) {
129
+ const { migrateLegacyLibrary } = await import("../src/library.js");
130
+ const m = migrateLegacyLibrary();
131
+ if (m.moved) console.log(`✓ biblioteca movida para ${m.target} (o caminho antigo ${m.legacy} continua levando até ela)`);
132
+ else if (m.error) console.log(`! não deu para mover a biblioteca para ${m.target} (${m.error}); sigo usando ${m.legacy}`);
133
+ else if (m.skipped === "as duas têm conteúdo") console.log(`! há apresentações em ${m.legacy} e em ${m.target}; uso ${m.target}. Junte as duas pelo Explorer se quiser.`);
134
+ }
127
135
  switch (cmd) {
128
136
  case "napkin":
129
137
  case "visual": {
package/docs/ANDAMENTO.md CHANGED
@@ -8,6 +8,382 @@ começar. Trabalho em curso vai para o GitHub (commit + push) a cada etapa, nunc
8
8
 
9
9
  ---
10
10
 
11
+ ## Próximas frentes (levantadas em 08/10/2026, ainda não começadas)
12
+
13
+ **Para quem pega isto numa sessão nova, sem a conversa de origem.** O projeto é o **sagadeck**:
14
+ - Repositório GitHub `naruminho/sagadeck`, clonado em `C:\Users\narum\src\sagadeck`, branch `main`.
15
+ - Publicado no npm como `sagadeck` (1.5.0, com as mudanças de 08 e 09/10).
16
+ - Ferramenta Node (ESM) que transforma apresentações escritas em YAML em HTML/PPTX.
17
+ - Tem um editor web, o Studio (`sagadeck studio`, porta 3517).
18
+ - Tem uma IA (via modelrelay em `http://127.0.0.1:8765/v1`) que cria e edita decks, inclusive a partir de PDFs de
19
+ artigos científicos para apresentar em congresso.
20
+
21
+ Os itens abaixo vieram de duas rodadas de 08/10/2026, ambas descritas nas seções logo abaixo deste diário:
22
+ - **Paper → congresso.** Geramos decks a partir de três PDFs, olhamos o resultado e corrigimos o motor (figuras,
23
+ equações, crítica, autoria, idioma).
24
+ - **Biblioteca no OneDrive.** A pasta das apresentações passou de `C:\Users\narum\sagadeck` para a pasta Documentos
25
+ do Windows, que nesta máquina é redirecionada para o OneDrive: `C:\Users\narum\OneDrive\Documents\sagadeck`. O
26
+ caminho antigo virou junção.
27
+
28
+ **Ordem combinada com quem mantém o projeto (Narumi):** 1, depois 4, depois 8: os três entraram em 08/10 (seções
29
+ datadas abaixo). O resto fica para depois e só entra se for pedido. Antes de começar, leia o `CLAUDE.md`
30
+ (regras). Para cada item:
31
+ - teste que falha antes da correção;
32
+ - `npm test` passando;
33
+ - uma branch por item, PR e merge na hora, sem perguntar;
34
+ - este diário atualizado no mesmo commit. Item feito sai desta lista e vira uma seção datada com o que entrou.
35
+
36
+ **OneDrive (a biblioteca agora mora em `C:\Users\narum\OneDrive\Documents\sagadeck` e sincroniza)**
37
+
38
+ 2. **Cache fora da nuvem.** A lixeira passou a durar um dia (seção "Lixeira de um dia" abaixo). Sobram `.cache`
39
+ (5 MB) e `.historico` indo para o OneDrive; só pesa se a pasta Documentos estiver no OneDrive (comum no Windows 11
40
+ e em empresa, mas não universal). O histórico de versões talvez deva continuar junto do deck (portável).
41
+ 3. **Arquivos só na nuvem (Files On-Demand).** Com espaço liberado, o OneDrive deixa só o marcador do arquivo, e
42
+ ler o conteúdo força o download. Conferir se listar a biblioteca (`openLibrary`, `/api/library`) lê o YAML de
43
+ cada deck; se lê, listar só pelo nome/metadado e abrir o conteúdo sob demanda.
44
+
45
+ ## Pacote Python: escape inválido numa docstring — 09/10/2026
46
+
47
+ Antes da release 1.5.0. `python/sagadeck/api.py` tinha "Documentos\sagadeck" numa docstring: `\s` é escape inválido,
48
+ `SyntaxWarning` no Python 3.12 (a CI no Linux acusava; aqui, no 3.11, passava calado) e erro nas versões seguintes.
49
+ Virou "Documentos/sagadeck". Teste novo em `test/python-relay.test.js`: compila todo o pacote com `-W error` (qualquer
50
+ Python; falhava antes).
51
+
52
+ ## Crítica acionável: cada ponto vira um cartão com Aplicar e Ignorar — 09/10/2026
53
+
54
+ Item 7 das próximas frentes. A leitura crítica (botão do chat) chegava como um texto único, com opções gerais ("leve
55
+ os achados para os slides").
56
+
57
+ - Cada ponto vem com `id` e, quando o deck vai junto, o `slide` a que se liga (antes só o tipo "slide a rever" tinha;
58
+ regra no prompt de `critiqueMaterials`; número que não existe no deck é descartado).
59
+ - No chat, cada ponto é um cartão: tipo, título, texto, o trecho conferido e "Slide N" (leva até ele). **Aplicar**
60
+ vai ao slide e pede à IA só aquele ponto, mirando aquele slide (a autoria decide: achado no slide, crítica e
61
+ pergunta nas notes). **Ignorar** fica gravado (`/api/ai/critique/item`, `status` no `.sagadeck/leitura-critica.json`)
62
+ e o ponto sai do material que acompanha os próximos pedidos (`critiqueMaterial`).
63
+ - Teste (`test/studio-critique.test.js`): dois pontos viram dois cartões; slide inexistente não vira link; Ignorar
64
+ grava e tira o ponto do próximo pedido; Aplicar vai ao slide 2, pede o ponto e grava "aplicado". Falha sem a mudança.
65
+ - **Item 5 (equações que a visão não listou) já estava feito**: `assignEquations` põe as numeradas esquecidas em
66
+ `missed`, elas entram no inventário com a caixa exata do texto e passam pela mesma releitura do recorte
67
+ (`transcribeEquation`) que escreve o LaTeX das outras. Saiu da lista.
68
+
69
+ ## Studio avisa quando o código mudou por baixo dele — 09/10/2026
70
+
71
+ Continuação do incidente "nenhum slide abre" de 08/10: um Studio aberto antes de uma atualização segue com o servidor
72
+ velho, enquanto os arquivos da página vêm novos do disco. Corrigir a lista de scripts resolveu aquele caso, mas
73
+ qualquer mudança de API quebraria do mesmo jeito, em silêncio.
74
+
75
+ - `src/studio/code-version.js`: impressão do código (caminho, data e tamanho de cada arquivo de `src/`; no pacote do
76
+ pip, do motor empacotado). O Studio guarda a de quando subiu; `/api/code-version` diz se mudou (recalcula no máximo
77
+ a cada 3 s).
78
+ - `update-notice.js` (editor e biblioteca): confere ao abrir, ao voltar para a aba e a cada 30 s; mudou, mostra a
79
+ faixa "O sagadeck foi atualizado. Feche e abra o Studio de novo…", que dá para fechar.
80
+ - Teste (`test/studio-scripts.test.js`): o Studio sobe com uma raiz de código temporária (`codeRoot`, só para testes,
81
+ para não acender o aviso num Studio de verdade aberto ao lado); sem mudança, sem aviso; mudou a data de um arquivo,
82
+ editor e biblioteca mostram a faixa e ela fecha; zero erros de JavaScript. Falha sem o recurso.
83
+
84
+ ## Testes instáveis sob carga — 09/10/2026
85
+
86
+ Item 9 das próximas frentes. Testes que passavam sozinhos e caíam com a suíte inteira trocaram tempo fixo por espera
87
+ da condição de verdade:
88
+
89
+ - `developer-labs` (frame executa JavaScript): o clique chegava antes de o script do iframe ligar o `onclick` e o
90
+ resultado ficava 0. Espera o `onclick` existir e o texto virar 1 (e 0 depois do reinício).
91
+ - `motion-scenes`: comparava o quadro da animação depois de 100–300 ms. Agora espera o quadro mudar (anima) ou parar
92
+ de mudar (pausou fora do slide), com prazo.
93
+ - `library-ui` (aula de APIs ao vivo): só clica em Executar com o slide montado.
94
+ - **Defeito de verdade achado no caminho**: com `motion: none`, a cena de terminal começava digitando ("first l_")
95
+ porque só sabia do movimento reduzido pela mensagem da página, que sob carga chegava tarde. A cena agora nasce
96
+ sabendo (`still` no documento dela, `motionHTML` em `src/motion.js`). O teste de captura confere que, no instante em
97
+ que o texto aparece, ele já está completo; e um teste rápido confere o `still` no documento (falhava antes).
98
+
99
+ ## Geração por etapas: o aviso diz a etapa e o documento é lido em paralelo — 08/10/2026
100
+
101
+ Item 6 das próximas frentes. Gerar com documento leva minutos e a tela ficava em "Pensando…" sem dizer pensando em
102
+ quê; e o inventário do documento (a visão lendo página a página) rodava inteiro antes de qualquer outra coisa.
103
+
104
+ - **Quadro de etapas** (`src/ai/progress.js`, `stageBoard`): `generateDeck` passa cada etapa por ele (Entendendo o
105
+ pedido, Pesquisa, Leitura crítica, Lendo o documento, Escrevendo a apresentação, Conferindo as figuras do material,
106
+ Conferindo os números, Imagens, Revisão dos slides). Todo aviso sai como "Etapa: detalhe"; duas etapas ao mesmo
107
+ tempo aparecem juntas ("Lendo o documento: página 3 de 12… · Leitura crítica: …"). O evento leva `stages` (as em
108
+ curso) e `done` (as terminadas). A biblioteca mostra também o tempo decorrido.
109
+ - **Em paralelo** (`generateForStudio`): o inventário começa na hora e corre junto com entender o pedido, a pesquisa
110
+ e a leitura crítica (que usam só o texto; `worthCritique` aceita documento ainda sem inventário, marcado
111
+ `document`). A escrita espera o inventário (`pendingMaterials`). Se a geração para antes (a IA perguntou, deu
112
+ erro), o inventário é cancelado (`AbortController`) e a pasta fica livre.
113
+ - Testes (`test/ai.test.js`): o quadro com duas etapas juntas; a crítica começa enquanto o inventário ainda não
114
+ terminou (o inventário falso só termina depois que a crítica começa: com a ordem antiga, travava), a escrita recebe
115
+ o material inventariado e nenhum aviso sai sem etapa; e a pergunta antes de escrever cancela o inventário.
116
+
117
+ ## Lixeira de um dia — 08/10/2026
118
+
119
+ Pedido de Narumi: a lixeira da biblioteca guardava 30 dias e estava com 407 MB (23 apresentações, quase todas
120
+ gerações de teste), tudo sincronizando com o OneDrive. Agora guarda um dia (`TRASH_DAYS = 1` em `src/library.js`;
121
+ `purgeOld` apaga de vez o que passou disso). Textos da biblioteca e README falam em um dia. A lixeira do projeto
122
+ (`.sagadeck/lixeira`, arquivos dentro de uma apresentação) não muda. Teste: `test/library.test.js` (excluída há uma
123
+ hora continua restaurável; há dois dias some do disco).
124
+
125
+ ## Studio aberto antes da atualização não abria slide — 08/10/2026
126
+
127
+ Retorno logo depois do item 8: "tentando abrir um slide e não abre". O Studio da pessoa tinha subido antes do merge.
128
+ O servidor lia o `app.js` do disco a cada pedido (veio o novo, que chama `window.SagaHeaderFooter`), mas a lista de
129
+ scripts que ele entregava (`PUBLIC_SCRIPTS`) era fixa na memória: `header-footer.js` e `preferences-ui.js` davam 404,
130
+ o `app.js` quebrava ao carregar e nada abria. Reiniciar o Studio resolvia; a correção evita a próxima vez.
131
+
132
+ - `publicScript` (`src/studio/public-files.js`): todo `.js` direto na pasta `public` é entregue, decidido a cada
133
+ pedido olhando o disco (só nome simples: nada de subir de pasta). A lista fixa acabou; módulo novo não precisa
134
+ mais ser registrado em lugar nenhum além do `index.html`.
135
+ - Teste (`test/studio-scripts.test.js`): todo `<script src>` do `index.html` e do `library.html` responde 200, e um
136
+ módulo criado depois que o Studio subiu também (falhava com 404 antes); `..`, arquivo inexistente e nome estranho
137
+ não passam.
138
+
139
+ ## Bancada de qualidade da geração a partir de paper — 08/10/2026
140
+
141
+ Item 4 das próximas frentes. Saber se a geração a partir de PDF melhorou dependia de gerar decks e olhar um por um.
142
+ Agora há uma avaliação repetível do motor: gera a partir de PDFs quaisquer e dá nota ao que saiu.
143
+
144
+ - **Nota** (`src/ai/bench.js`, `scoreDeck`): de 0 a 100 por quesito, com as mesmas ferramentas da autocrítica:
145
+ figuras/tabelas numeradas com slide (`uncoveredVisuals`), recorte de figura sem legenda nem "Fonte:" dentro (linha
146
+ de legenda/crédito da camada de texto do PDF cruzando a caixa do recorte), equações numeradas do texto com LaTeX
147
+ (`equationGroups` × inventário), números na tela sem base no documento (`unsupportedNumbers`), autor do documento
148
+ e não o das Preferências, sem votação em deck acadêmico, sem slide de frase gigante (`auditText`) e idioma pedido
149
+ (texto e `lang`). Quesito sem como medir fica "—" (não conta como bom). Total = média.
150
+ - **Mesmo caminho do Studio**: as opções da geração saíram do servidor para `src/studio/generate.js`
151
+ (`generateForStudio`: Preferências, anexos com inventário na pasta do deck, revisão pelos slides renderizados); o
152
+ `generateIntoLibrary` e a bancada usam a mesma função. A bancada passa Preferências fixas (autor de mentira para
153
+ pegar autor errado, sem perguntar, sem imagens geradas).
154
+ - **Rodar** (lento; ao vivo): `SAGADECK_LIVE=1 SAGADECK_BENCH_DIR=<pasta com PDFs> node --test test/bench-live.test.js`.
155
+ Gera a partir de cada PDF da pasta com um pedido genérico (`SAGADECK_BENCH_PEDIDO` troca; `SAGADECK_BENCH_IDIOMA`
156
+ liga a conferência de idioma). Os PDFs são exemplos quaisquer: nada de caso fixo, nome de paper ou de pessoa no
157
+ repositório. O objetivo é medir o motor, não acertar um deck.
158
+ - **Relatório**: `<data>-<versão>.json` e `.md` em `SAGADECK_BENCH_OUT` (senão `<SAGADECK_BENCH_DIR>\sagadeck-bancada`),
159
+ com o quadro PDF × quesito, a diferença para a rodada anterior (a média só quando os PDFs são os mesmos) e o que
160
+ puxou cada nota para baixo (figura que faltou, recorte com legenda, número sem base).
161
+ - Testes: `test/bench.test.js` (cada quesito num deck e material montados à mão, legenda na coluna vizinha não
162
+ conta, relatório com a comparação) e `test/bench-live.test.js` (só com `SAGADECK_LIVE=1` e `SAGADECK_BENCH_DIR`).
163
+
164
+ ## app.js abaixo do limite: Preferências e Cabeçalho/Rodapé em módulos — 08/10/2026
165
+
166
+ Item 8 das próximas frentes. O `src/studio/public/app.js` estava com 249.491 dos 250.000 bytes que a trava do monólito
167
+ (`test/guards.test.js`) permite: qualquer acréscimo quebrava. O chat já tinha saído (`chat.js`); saíram dois blocos
168
+ inteiros e autocontidos, no molde de `slide-select.js` (fábrica que recebe o estado e os ajudantes e devolve a API):
169
+
170
+ - `header-footer.js` (`window.SagaHeaderFooter`): modelos prontos, campos com variáveis e prévia do cabeçalho/rodapé.
171
+ - `preferences-ui.js` (`window.SagaPrefs`): a tela única de Preferências, com busca e gravação automática.
172
+ - Carregados no `index.html`, antes do `app.js` (o servidor entrega todo `.js` da pasta `public`; ver a seção
173
+ seguinte).
174
+ - `app.js` foi a 235.619 bytes; o limite desceu para 240.000 (a trava continua sendo catraca: sobra espaço para
175
+ ajustes pequenos, recurso novo vai para módulo próprio).
176
+ - Testes: os de Preferências e de cabeçalho e rodapé do `test/studio.test.js` (clicam de verdade e conferem o deck e
177
+ o arquivo salvos, sem erro de JavaScript) passam iguais; comportamento não mudou.
178
+
179
+ ## Gravação tolerante a arquivo travado (OneDrive) — 08/10/2026
180
+
181
+ Item 1 das próximas frentes. Com a biblioteca no OneDrive, a sincronização (e antivírus, indexador) segura o arquivo
182
+ por um instante e o `rename` falha com `EPERM`/`EBUSY`/`EACCES`: o salvamento da pessoa se perdia com erro.
183
+
184
+ - `renameRetry` (`src/fs-retry.js`): tenta de novo só nesses três códigos, com espera curta e crescente (20 → 450 ms,
185
+ ~1 s no total); outro erro (disco cheio, destino inexistente) sobe na hora. Espera síncrona (`Atomics.wait`), para
186
+ servir aos chamadores síncronos sem mudar a assinatura deles.
187
+ - Usado em todo rename do código: `writeDeckFile`, biblioteca (lixeira, restaurar, mover, renomear deck e tópico,
188
+ publicar a geração, migração), arquivos do projeto, Preferências, conversa do chat, links compartilhados e
189
+ ambientes do slide api.
190
+ - Testes (`test/deck-file.test.js`, `test/library.test.js`): stub do `fs.renameSync` que falha N vezes com cada código
191
+ e o deck é gravado; erro de outro tipo sobe na primeira tentativa; trava que não solta desiste em ~1 s sem estragar
192
+ o arquivo; lixeira/restaurar/mover/renomear com a pasta travada; e uma trava de código: `fs.renameSync` direto em
193
+ `src/` ou `bin/` faz o teste falhar.
194
+
195
+ ## Biblioteca padrão em Documentos\sagadeck — 08/10/2026
196
+
197
+ Pedido: a biblioteca padrão no Windows é a pasta `sagadeck` dentro de Documentos (antes, `~/sagadeck`, direto na
198
+ pasta do usuário). `defaultLibraryRoot`: `SAGADECK_HOME`, senão `<Documentos>\sagadeck` no Windows (a pasta
199
+ conhecida "Personal" do registro: a que o Explorer mostra, inclusive redirecionada; aqui é
200
+ `C:\Users\narum\OneDrive\Documents`, então a biblioteca sincroniza com o OneDrive) e `~/sagadeck` fora dele.
201
+ `migrateLegacyLibrary` (na partida do `sagadeck`): move a biblioteca antiga inteira (mesma unidade: instantâneo) e
202
+ deixa uma junção no caminho antigo; não mistura se as duas têm conteúdo; falhou, a antiga continua valendo (nunca
203
+ abre vazia). CLAUDE.md, README, ajuda, MCP e Python atualizados. Teste: `test/library.test.js`.
204
+
205
+ ## Apresentação da Maria Clara em inglês — 08/10/2026
206
+
207
+ Gerada pelo caminho do Studio ("…que a Maria Clara vai fazer no ICFM10 sobre o artigo dela, em inglês"): 19 slides,
208
+ `lang: en`, autor "Maria Clara Fava et al.", sem votação, figuras inteiras, trade-off em gráfico. Problemas do motor:
209
+
210
+ - **Números em português num deck em inglês**: contador, gráficos, mapas, calculadora e laboratório de decisão
211
+ formatavam sempre em pt-BR ("1.403", "0,93"). `src/locale.js`: o idioma do deck (`lang`) vale para os números
212
+ (build define antes de renderizar; na apresentação, `<html lang>`); ler "1,403"/"37.67%" segue o idioma. Deck
213
+ gerado sem `lang` ganha o idioma pelo texto (`guessDeckLang`, palavras de ligação).
214
+ - **Precisão do paper perdida**: "0.90" sem aspas virava 0.9 no YAML (tabela do NSE em inglês com 0.9, 7.8, 0.2).
215
+ Em tabela (rows/head/cells) e em value exibido, o número fica como foi escrito; dado de gráfico continua número. E o
216
+ gráfico mostrava 1 casa abaixo de 10 (0.93 → 0.9) e 0 acima (37.67 → 38): agora as casas do próprio valor, até 2.
217
+ - **Texto vazando da caixa do diagrama flow** ("Low-lying areas near the drainage network" a 36 px fixos):
218
+ `boxFontSize` simula a quebra e desce até caber.
219
+ - Nome da pasta cortado no meio da palavra ("…Urban Flood Predic"): corta no último espaço antes de 80.
220
+ - Sem texto do motor em português no HTML (conferido no build: nenhum rótulo automático em pt).
221
+
222
+ ## Retorno dos decks do ICFM10: autor errado, figura cortada, "^^≠^^", votação — 08/10/2026
223
+
224
+ - **Autor**: os dois decks saíram "Narumi Abe" (o autor das Preferências), não Maria Clara Fava. Bug da rodada
225
+ anterior: a regra "autor = a pessoa apresenta o próprio trabalho" + o autor padrão viraram "quem usa é o autor do
226
+ artigo". Agora, com documento anexado, o autor das Preferências não vai como padrão nem é colado no deck; regra:
227
+ quem assina é quem assina o documento (o primeiro apresenta em `autor`; em `livre`, quem apresenta vai em `role`).
228
+ - **Figura 2 cortada**: a caixa da visão era larga demais (a imagem cobria 44% dela) e a regra exigia 50%: caía no
229
+ corte pela camada de texto, que comia a ponta do mapa e trazia um pedaço da linha de cima. Imagem de tamanho de
230
+ figura (≥ 1% da página) que cobre um quarto da caixa já é a figura.
231
+ - **"^^≠^^"** no compare: o `vs` saía com esc(), sem a marcação. Corrigido, e a revisão de texto agora renderiza o
232
+ slide e acusa qualquer marcação crua visível (^^, ==, **), fora dos slides de código: pega os outros campos assim.
233
+ - **Votação no journal club**: apresentação acadêmica (deck de artigo, congresso, defesa, seminário, journal club)
234
+ não leva enquete, votação, quiz ou cronômetro sem pedido de interação: regra no prompt e achado da revisão.
235
+ - Prova ao vivo ("apresentação que a Maria Clara vai fazer no ICFM10 sobre o artigo dela"): capa "Maria Clara Fava et
236
+ al. · UFSCar", `autoria: autor`, sem votação, Figura 2 inteira. Achou outro defeito: duas capas idênticas (até as
237
+ notes; o "slide repetido" que o diário já registrava). Cópia exata sai na geração (`dropDuplicateSlides`), e
238
+ mesmo layout + mesmo título vira achado da revisão.
239
+ - **Opinião sem foco** ("o que você acha desse slide?"): a foto do slide puxava a resposta para o design. Regra 1c:
240
+ responder conteúdo PRIMEIRO (fiel ao material? falta o porquê, o número? o que a banca pergunta?) e forma depois,
241
+ com opções para aprofundar cada um; foco dito pela pessoa vale sozinho. Ao vivo, no slide da Tabela 1 do ICFM10:
242
+ apontou que o achado mais forte (HYMOD empata com o HEC-HMS) passava batido e só depois o texto lateral longo.
243
+ - Biblioteca: os decks de teste do ICFM10 superados foram para a lixeira (recuperáveis); ficaram o do congresso
244
+ (Maria Clara) e o do journal club.
245
+
246
+ ## Leitura crítica do material, autoria e origem do conteúdo — 08/10/2026
247
+
248
+ Retorno: num brainstorm pelo chat, a IA achou o que a geração não achou (o resumo do ICFM10 promete variáveis
249
+ socioeconômicas que o método não usa; o trade-off pico × volume escondido na tabela; o donut mostrando composição da
250
+ amostra como resultado). Pedido: por que a geração não fez isso; é válido "interferir" se o original é ruim; botão de
251
+ criticar; saber o que é do paper e o que é inclusão do sagadeck; e liberdade total fora do caso "autor apresenta o
252
+ próprio paper".
253
+
254
+ - Causa: a geração lia o paper para APRESENTAR, nunca para criticar. Agora há uma etapa de **leitura crítica**
255
+ (`src/ai/critique.js`): inconsistências, achados que passam batido, perguntas prováveis, limitações, slide que
256
+ representa mal o material e pontos fortes, cada item com trecho LITERAL do material, conferido pelo código (letras
257
+ e números, tolerando os espaços e hifens do PDF): sem trecho no texto, o item é descartado (anti-alucinação).
258
+ Roda na geração quando há documento (vai no pedido e fica em `.sagadeck/leitura-critica.json`) e no botão
259
+ **Leitura crítica** do chat (`/api/ai/critique`, ícone scan-search): vira mensagem com opções, nada muda nos slides,
260
+ e acompanha os próximos pedidos rotulada "feita pelo sagadeck, NÃO pelo autor".
261
+ - **Autoria** (`context.autoria`): `autor` (congresso, simpósio, defesa: fiel ao material; o achado do material vai ao
262
+ slide, a crítica e as perguntas vão nas notes "Prepare-se: …") × `livre` (aula sobre o trabalho de outros, journal
263
+ club, resenha, divulgação, tema geral: conteúdo próprio liberado). Responde à dúvida "é válido interferir": no
264
+ modo autor, o sagadeck não reescreve a ciência do paper, prepara o autor; a decisão de mudar é da pessoa.
265
+ - **Origem** (`provenance: material | derivado | proprio` + `provenanceNote`; `origin` já era a etimologia do layout
266
+ definition): selo na miniatura do Studio para o que o sagadeck incluiu ou calculou; a apresentação não mostra.
267
+ - Ao vivo (deck do ICFM10): 12 pontos em 153 s, todos com trecho conferido; repetiu os do brainstorm e achou mais:
268
+ PEV e PBIAS idênticos na Tabela 1 (conferido no PDF: mesmas linhas, sinais trocados), validação com um evento só,
269
+ resumo promete "flood extents" que não existem, bacia "com poucos dados" muito bem instrumentada, referência
270
+ interna errada (2.1.1 × 2.2.1).
271
+ - Geração ao vivo, mesmo paper, dois pedidos: "apresentação oral em congresso" → `autoria: autor`, todo slide com
272
+ provenance, o trade-off virou slide ("Volume simples, pico detalhado"), o donut virou "a base de treino tem três
273
+ classes bem desiguais" (derivado), e a crítica foi para as notes como "PREPARE-SE" (PEV = PBIAS no slide da
274
+ tabela, socioeconômicas no das variáveis, referência errada nas limitações). "Journal club da disciplina" →
275
+ `autoria: livre`: a crítica virou conteúdo marcado `proprio` (Prometido × entregue; Os números que não fecham;
276
+ Três furos no desenho; pergunta para a turma). Essa levou 43 min: o modelo travou pensando e a tentativa sem
277
+ raciocínio (da rodada anterior) destravou a tarefa.
278
+ - Testes: `test/critique.test.js` (trecho conferido × inventado, bloco no prompt, geração com a leitura),
279
+ `test/studio-critique.test.js` (botão, trecho na conversa, arquivo salvo, próximo pedido leva a leitura, selo).
280
+
281
+ ## O chat pode VER o material anexado (ver:) — 08/10/2026
282
+
283
+ Retorno: no chat do deck do ICFM10, "vc tem acesso ao pdf?" levou a IA a dizer que "consegue ler as figuras
284
+ recortadas e abrir a página inteira", o que era falso: do documento o chat recebe o texto e o inventário (legendas,
285
+ caminhos), nunca as imagens. Sem jeito de olhar, ela não conseguia consultar o material de verdade.
286
+
287
+ - `ver: [arquivos]` na resposta da IA (como o `test:` dos slides api): o Studio carrega as imagens pedidas (só de
288
+ dentro da pasta da apresentação, até 6: recortes em items[].image e páginas inteiras em pages), chama de novo com
289
+ elas anexadas ("material: <arquivo>") e a IA responde já vendo; até 2 rodadas (`lookableFiles`, `ai-chat-route.js`).
290
+ - Regra no formato da resposta: pedir para ver antes de responder sobre o que a figura mostra; nunca dizer que viu o
291
+ que não pediu; nunca dizer que não tem acesso ao material.
292
+ - Ao vivo (deck do ICFM10, modelo de verdade): "qual a ordem das 5 variáveis mais importantes da Figura 4b?" — pediu
293
+ o recorte e a página 6, leu hand ≈ 100, elevation ≈ 45… e avisou que são leituras do eixo; 22 s, nada mudou.
294
+ - Teste: `test/document-visuals.test.js` (pede, recebe a imagem rotulada, caminho para fora da pasta recusado).
295
+
296
+ ## Paper para congresso, 2ª rodada: equações, redesenho com volta ao original, dados corrompidos — 08/10/2026
297
+
298
+ Pedido: equação não precisa de recorte se vira LaTeX (e, se precisar, que o recorte preste); gráfico pode ser
299
+ redesenhado, desde que o chat consiga voltar ao original; a IA cria gráficos dos números do texto por iniciativa.
300
+ Teste com o paper do eucalipto (o das equações) e o ICFM10 (Aricanduva).
301
+
302
+ - **Equação pela camada de texto** (`equationGroups`, `assignEquations`): equação de Word/LaTeX é texto (𝑑, 𝜋, ∑);
303
+ os grupos de caracteres matemáticos da página dão a caixa exata (sem a vizinha, a prosa e o "(4)"). A visão punha
304
+ as caixas deslocadas uma equação para baixo (a Eq. 4 sumia e a 5 levava o recorte e o LaTeX da 6): agora casa
305
+ pelo número impresso, depois pelo conteúdo (letras do LaTeX × texto do PDF, 𝑅𝑀𝑆𝐸→RMSE), por último pela
306
+ posição. Numerada que a visão esqueceu entra; item repetido sai; equação como imagem cai na régua da imagem.
307
+ - **Releitura no recorte** (`transcribeEquation`): cada equação é relida na própria imagem; a leitura que encolhe
308
+ (recorte parcial) não troca a da página; "\quad (3)" sai. Com LaTeX, o inventário vai ao modelo SEM o arquivo do
309
+ recorte (`promptInventory`): o slide usa a fórmula nativa. Resultado: 16/16 equações dos dois papers corretas.
310
+ - **Tabela sem rows** relida no recorte (`transcribeTable`): vira table nativa e a cobertura reconhece.
311
+ - Um item com caixa inválida sai sozinho (antes a página inteira virava uma imagem só).
312
+ - "Figure 5 shows…" não é legenda (`captionLineStrict`): parava de cobrar "legenda sem arte" na página.
313
+ - **Redesenho com volta**: `sourcePx` (tamanho nativo da imagem embutida) no inventário; regra: esquema → diagram
314
+ nativo, gráfico com valores no paper → chart nativo, gráfico sem dados/ilustração → modelo de imagem, mapa e foto
315
+ ficam. O redesenho guarda `original` no elemento (antes o caminho sumia com o image_ref); reconstrução nativa
316
+ leva `sourceFigure` no slide; "volte ao original" troca o visual por ele (REFERENCIA). Iniciativa: números do
317
+ texto/tabelas viram chart criado pela IA, com `source`.
318
+ - **Dado corrompido**: `[07/04/2017, HEC-HMS, 0,93, 0,97]` partia "0,93" em 0 e 93 (YAML) e a tabela do ICFM saiu
319
+ com NSE 0 e R² 93, colunas deslocadas, sem erro. `quoteFlowDecimals` põe entre aspas "dígitos,dígitos" sem espaço
320
+ em lista separada por ", " (`[10,20,30]` fica); `sanitizeCheck` recusa tabela com linha de tamanho diferente do
321
+ cabeçalho (volta para a IA).
322
+ - **"NaN" e "km^2^"**: `number` com valor "37,67%" ou "1521 km^2^" mostrava NaN (o contador só aceitava número):
323
+ `parseCounterValue` lê no formato brasileiro e separa prefixo/sufixo; expoente/índice viram ²/₂; valor do
324
+ `stats` passa pela marcação.
325
+ - **Título encolhido pela IA** (titleSize 40 "para dar espaço à figura"): regra no prompt e achado da revisão.
326
+ - **Tarefa parada horas em "Pensando…"**: o relay manda "estou vivo" e o raciocínio enquanto o modelo pensa, e cada
327
+ pedaço zerava o relógio; um modelo em laço nunca terminava. Agora o limite da 1ª palavra de TEXTO (600 s) vale
328
+ mesmo com os sinais de vida (`AI_THINKING_LOOP`), e a chamada ganha uma tentativa a mais SEM raciocínio (a mesma
329
+ tarefa sai em segundos). Aconteceu duas vezes seguidas com o DeepSeek Flash na conferência de cobertura.
330
+ - **Checagem de números** (`unsupportedNumbers` + `checkNumbers`, na geração e no chat com anexo): todo número
331
+ visível (texto e dados de gráfico/tabela) que não está no material volta para a IA corrigir, mostrar a conta ou
332
+ tirar; arredondamento do valor do paper vale, contagem pequena não é cobrada. Pegou "ANOVA p = 0,109" que o artigo
333
+ do eucalipto não tem (lido errado do gráfico); nos outros dois decks, nenhum alarme falso.
334
+ - Resultado (mesmos PDFs): eucalipto com o fluxograma como diagram nativo (`sourceFigure`), equações nativas com as
335
+ variáveis explicadas, dois gráficos criados dos números do texto; ICFM10 com a tabela certa, km² e todas as
336
+ figuras. "Volte para a figura original" pelo chat (modelo de verdade) trocou o donut pelo mapa em 8 s, citando o
337
+ `sourcePx` baixo. Regra nova: gráfico criado por iniciativa não substitui mapa ou foto.
338
+
339
+ ## Apresentação de congresso a partir de paper: figuras, cobertura e frase gigante — 08/10/2026
340
+
341
+ Retorno de quem usa: figuras ignoradas, com a legenda junto, cortadas ou fora de proporção; conteúdo fraco (contexto,
342
+ objetivos, metodologia); slides de uma frase gigante; a IA sem senso crítico/ferramenta para se corrigir. Método:
343
+ dois PDFs quaisquer (Rev. Bras. Cartogr. 2025, volume de eucalipto por ETR; RBGF 2020, LiDAR na bacia do Beberibe)
344
+ gerados pelo caminho do Studio (`/api/ai/context` + `/api/library/decks/ai`, modelo do modelrelay), tópico
345
+ "Laboratório congresso" da biblioteca. Os decks são diagnóstico, não foram retocados.
346
+
347
+ - **Recorte pela imagem embutida** (`snapToImages`, `pdfLayout` em `src/ai/document-visuals.js`): o pdf.js dá a
348
+ posição exata de cada imagem da página (lista de operações). Caixa da visão sobre imagem(ns) vira a imagem (ou a
349
+ união dos painéis): sem legenda, sem "Fonte:", sem prosa, proporção do original. Antes: legenda de cima curta
350
+ (ABNT, centralizada) entrava sempre (a regra exigia linha mais larga que meia figura), "Fonte: Os autores" e o
351
+ parágrafo de baixo também, e os mapas de dois painéis do RBGF saíam em dois recortes com tira do vizinho.
352
+ Fundo de página escaneada e logo pequeno não servem de régua; prancha enorme fica com a caixa aparada.
353
+ - **Duplicatas fundidas** (`mergeDuplicateCrops`): dois itens no mesmo recorte viram um, com a legenda numerada.
354
+ - **Camada de texto** (gráfico vetorial, tabela, equação): legenda de cima de qualquer largura e linha de crédito
355
+ (`creditLineStart`: Fonte/Source/Elaboração) ficam de fora; linha de prosa passando pela borda não estica o recorte.
356
+ - **Margem branca aparada** no recorte (`cropRegions` com `trim`; a tinta é medida antes de aparar) e o inventário
357
+ traz `width`/`height` do recorte. Cache do inventário: `visualVersion` 5 (recorta de novo o que já foi anexado).
358
+ - **Cobertura** (`uncoveredVisuals` + `coverDocumentVisuals` em `deck-ai.js`): `ensureVisualCoverage` existia mas
359
+ ninguém chamava. Agora, depois do rascunho, figura/tabela NUMERADA sem slide volta para a IA encaixar no ponto da
360
+ narrativa (uma rodada; o resto vai em `coverage.missing`, sem slide enfiado no fim). Vale no Criar com IA e no
361
+ chat quando a mensagem anexa documento e a resposta monta a maior parte do deck (`changed` exposto pelo editDeck).
362
+ - **Revisão de texto sem visão** (`auditText` em `src/ai/quality.js`, sempre roda dentro da revisão): frase longa
363
+ em statement/headline/quote e excesso de telas de frase única (mais de 2 ou 15%) viram achados para a correção.
364
+ - **Legenda colada na imagem** (`clearCaptionEdges`): a caixa de texto do pdf.js termina na linha de base, então as
365
+ pernas da legenda logo acima da imagem entravam como uma tira; linha de legenda/crédito na borda empurra a borda.
366
+ - **Motor**: `full` com figura do documento (ou `fit: contain`) e texto vira a composição de figura inteira (título
367
+ no alto, legenda embaixo; decidido em `inferLayout` via `fullAsFigure`, para a casca do slide não ser a de página
368
+ inteira que escondia o título), mesmo com `overlay: none`; `headline` longa sai em title/h2 (era o objetivo
369
+ inteiro a 300 px); cartão cujo texto é só fórmula mostra a fórmula grande (`cd-math`).
370
+ - **Proporção e corte**: figura do documento é sempre `contain` (o cover automático de até 20% comia eixo e
371
+ legenda; `fill`/`stretch` achatavam o mapa). `crop:` em caixa de outra proporção esticava: a apresentação mede a
372
+ caixa e encaixa a região inteira (`fitCrops` em `src/runtime/fit.js`, `data-crop` no `<img>`).
373
+ - Antes × depois (mesmos PDFs, mesmo modelo): Beberibe 16 → 24 slides, 4 → 7 figuras, nenhuma com texto por cima,
374
+ objetivo virou lista com três objetivos, arco completo; eucalipto 21 slides, todas as figuras limpas (antes com
375
+ legenda, "Fonte" e prosa no recorte). Ainda aberto: recorte de equação pela visão é impreciso (pega a vizinha e a
376
+ prosa); como toda equação vem com `latex`, o slide usa a fórmula nativa e o recorte não aparece.
377
+ - Testes antigos que falhavam na main: `api-ai-loop` (o mock não previa a decisão de pesquisa do chat, fase 2) e
378
+ o da exploração (mesmo achado em todas as rodadas, desde a regra "achado idêntico encerra as tentativas").
379
+ - **Prompt**: arco de apresentação de paper (contexto com dado, lacuna, objetivo geral/específicos em slide de
380
+ conteúdo, área/dados, método com variáveis e unidades, cada figura numerada no seu resultado com título-afirmação,
381
+ discussão, conclusões, limitações) e composição pela proporção do recorte. REFERENCIA: `full` e `headline`.
382
+ - Testes: `test/document-visuals.test.js` (PDF real do Chrome com legenda, imagem 2:1, "Fonte" e painel duplicado;
383
+ snap, fusão, crédito, legenda curta, borda da legenda, cobertura pelo chat), `test/ai.test.js` (cobertura na
384
+ geração, auditText), `test/engine.test.js` (full, headline, cartão com fórmula), `test/fit-wide.test.js` (figura
385
+ do documento contain, crop sem esticar, no navegador).
386
+
11
387
  ## Avaliação fora da hidrologia — 03/10/2026
12
388
 
13
389
  - Plano: `docs/PLANO-TESTE-DESINFORMACAO.md`.
@@ -66,7 +66,7 @@ slides:
66
66
  | `back` | id (ou número) do slide para onde o botão **Voltar** do canto leva; o botão mostra o título do destino |
67
67
  | `next` | id (ou número) do slide para onde o avanço leva **no fim deste slide** (o fim de um caminho volta ao mapa, em vez de seguir a ordem) |
68
68
 
69
- Títulos equilibram as linhas sem quebrar palavras arbitrariamente. A hifenização automática respeita o idioma do deck (`lang`, padrão `pt-BR`).
69
+ Títulos equilibram as linhas sem quebrar palavras arbitrariamente. A hifenização automática respeita o idioma do deck (`lang`, padrão `pt-BR`). Deck em outro idioma grava `lang` (`en`, `es`…): os números de contadores, gráficos e mapas seguem o idioma (em inglês, `1,403` e `0.93`).
70
70
 
71
71
  ## Marcação inline (qualquer texto)
72
72
 
@@ -110,8 +110,8 @@ Tabela em markdown no meio de um texto (`problem`, `body`, `text`, passo do `sol
110
110
  | `canvas` | `elements: [{…, x, y, w, h}]` | posicionamento absoluto em 1920 × 1080 |
111
111
  | `end` | `title, subtitle, contacts, figure, qr, qrLabel` | encerramento; `qr: <link>` põe um QR code ao lado (ex.: LinkedIn) |
112
112
  | `references` | `title, items` | fontes (2 colunas) |
113
- | `headline` | `kicker, text, as, size, caption` | manchete: uma frase enorme ocupando o slide |
114
- | `full` | `figure` (ou `image`/`image_prompt`), `kicker, title, caption, overlay: bottom\|left\|center\|none, fit, titleSize` | figura/imagem de página inteira com texto por cima; com `image_prompt` a IA gera a página toda |
113
+ | `headline` | `kicker, text, as, size, caption` | manchete: uma frase CURTA (até ~12 palavras) enorme ocupando o slide; frase longa sai menor (como no `statement`) e conta como slide de frase única (no máximo 2 por deck) |
114
+ | `full` | `figure` (ou `image`/`image_prompt`), `kicker, title, caption, overlay: bottom\|left\|center\|none, fit, titleSize` | figura/imagem de página inteira com texto por cima; com `image_prompt` a IA gera a página toda. Figura do documento (`contexto/visuais/…`) ou `fit: contain` com texto não leva véu: sai com o título no alto, a figura inteira e a legenda embaixo (como `image`) |
115
115
  | `kinetic` | `figure, beats: [{text, style, position, color, size, tag}], autoplay, interval` | frases curtas em sequência sobre uma cena; avanço manual ou automático |
116
116
  | `bento` | `title, tiles: [{title, text, value, icon, figure, size: big\|wide\|tall, hl}], cols, build` | mosaico de blocos de tamanhos diferentes |
117
117
  | `funnel` | `title, stages: [{title, value, text, hl}], build` | funil que afunila etapa a etapa |
@@ -539,7 +539,7 @@ aparecem (`showValues: true` força os valores).
539
539
  **SVG próprio**: `{ svg: "<svg viewBox='0 0 100 100'>…</svg>" }` — use `style="fill:var(--fg)"`, `var(--hi)`, `var(--em)` para seguir o tema.
540
540
  **Imagem**: `{ image: foto.jpg, fit: cover }` (caminho relativo ao YAML; é embutida no HTML). Sem `fit`, a imagem preenche a caixa, mas cabe inteira (`contain`) quando o corte passaria de 20% (gráfico com eixo e legenda na borda, esquema largo numa coluna alta); solta no fluxo (num `add`) e sem altura, não passa de 420 px. Para foto que pode ser cortada, `fit: cover`; para gráfico, `fit: contain`.
541
541
  **Imagem gerada por IA**: `{ image_prompt: "descrição visual, em inglês", fit: cover }` (sai sem texto: rótulos, números e títulos vão no slide; se a ilustração precisa de rótulos dentro dela, diga quais no prompt, em português e entre aspas: `with labels "Divisor de água", "Rio"`) — `sagadeck imagens deck.yaml` gera o arquivo em `imagens/` com o modelo de imagem e troca por `image:`.
542
- **Redesenhar uma figura do deck** (xerox, escaneada, borrada): `{ image_prompt: "Clean up and redraw THIS EXACT figure… (o que ela mostra, as cores)", image_ref: imagens/original/mapa.png, fit: contain }` — o modelo de imagem recebe a figura como base e devolve o redesenho; se não sair, fica a figura de base.
542
+ **Redesenhar uma figura do deck** (xerox, escaneada, borrada): `{ image_prompt: "Clean up and redraw THIS EXACT figure… (o que ela mostra, as cores)", image_ref: imagens/original/mapa.png, fit: contain }` — o modelo de imagem recebe a figura como base e devolve o redesenho; se não sair, fica a figura de base. Depois do redesenho, o elemento guarda a figura de base em `original` (ex.: `{ image: imagens/ia-1a2b.png, original: contexto/visuais/…/fig.png, fit: contain }`). Figura de documento anexado (PDF) traz no inventário `sourcePx` (tamanho nativo da imagem): esquema de caixas e setas borrado vira `diagram` nativo fiel; gráfico com os valores no paper vira `chart` nativo com os números exatos; gráfico sem os dados à mão e ilustração podem ser redesenhados assim; mapa e foto ficam. Reconstrução nativa de figura do documento leva no slide `sourceFigure: contexto/visuais/…/fig.png`. **Origem do conteúdo** (deck com material anexado): cada slide de conteúdo leva `provenance: material` (o que afirma está no material), `provenance: derivado` (reorganização, cálculo ou gráfico feito a partir dos números do material) ou `provenance: proprio` (inclusão da IA: contexto, analogia, exemplo, crítica), com `provenanceNote` curta quando não for `material`; o Studio mostra um selo na miniatura, a apresentação não. O deck grava `context.autoria`: `autor` (a pessoa apresenta o próprio trabalho: fiel ao material, crítica e perguntas prováveis nas notes) ou `livre` (aula, resenha, journal club, divulgação, tema geral: conteúdo próprio liberado, marcado). A **leitura crítica** do material (inconsistências, achados escondidos, perguntas prováveis, limitações, slide que representa mal o material, cada item com trecho literal conferido) fica em `.sagadeck/leitura-critica.json` e acompanha os pedidos ao chat. **Voltar ao original** ("mantenha a figura original", "volte para o gráfico do paper"): o visual do slide vira `figure: { image: <sourceFigure ou original>, fit: contain }`, sem mexer no texto. Números que o paper só dá no texto ou em tabela podem virar `chart` criado pela IA, com os valores exatos e `source` dizendo de onde vieram. Equação com `latex` no inventário vai como fórmula nativa (`math`, `equations`), nunca como o recorte.
543
543
 
544
544
  ## Notas / roteiro (`notes`)
545
545
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sagadeck",
3
- "version": "1.3.1",
3
+ "version": "1.5.0",
4
4
  "description": "Gerador de apresentações: YAML -> HTML animado + PowerPoint editável, com temas e figuras geradas na hora.",
5
5
  "type": "module",
6
6
  "bin": {