sagadeck 1.2.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 (233) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +305 -0
  3. package/SKILL.md +148 -0
  4. package/bin/sagadeck.js +511 -0
  5. package/docs/ANDAMENTO.md +1255 -0
  6. package/docs/EXPERIENCIAS.md +39 -0
  7. package/docs/PLANO-EXPERIENCIAS.md +39 -0
  8. package/docs/PLANO-TESTE-AULAS-TECNICAS.md +44 -0
  9. package/docs/PLANO-TESTE-DESINFORMACAO.md +38 -0
  10. package/docs/REFERENCIA.md +1131 -0
  11. package/package.json +59 -0
  12. package/src/adaptive-layouts.js +18 -0
  13. package/src/ai/art-direction.js +8 -0
  14. package/src/ai/commands.js +130 -0
  15. package/src/ai/context.js +245 -0
  16. package/src/ai/deck-ai.js +1135 -0
  17. package/src/ai/directions.js +74 -0
  18. package/src/ai/document-materials.js +49 -0
  19. package/src/ai/document-visuals.js +215 -0
  20. package/src/ai/evaluation.js +31 -0
  21. package/src/ai/ground.js +55 -0
  22. package/src/ai/llm.js +292 -0
  23. package/src/ai/quality.js +51 -0
  24. package/src/ai/relay.js +45 -0
  25. package/src/ai/staged-generation.js +24 -0
  26. package/src/ai/transform.js +858 -0
  27. package/src/ai/usage.js +17 -0
  28. package/src/ai/variety.js +80 -0
  29. package/src/ai/video-frames.js +24 -0
  30. package/src/ai/video-generation.js +126 -0
  31. package/src/ai/web-operation.js +31 -0
  32. package/src/algo-catalog.js +153 -0
  33. package/src/algo-trace.js +139 -0
  34. package/src/api-client.js +514 -0
  35. package/src/api-collections.js +14 -0
  36. package/src/api-demo.js +222 -0
  37. package/src/aspect.js +40 -0
  38. package/src/build.js +323 -0
  39. package/src/carousel.js +56 -0
  40. package/src/chrome.js +65 -0
  41. package/src/code-highlight.js +68 -0
  42. package/src/code-lab-browser.js +22 -0
  43. package/src/code-lab.js +3 -0
  44. package/src/code-language.js +52 -0
  45. package/src/csv.js +74 -0
  46. package/src/decision-lab.js +20 -0
  47. package/src/deck-file.js +119 -0
  48. package/src/diagram/napkin-examples.js +13 -0
  49. package/src/diagram/napkin.js +539 -0
  50. package/src/docx.js +128 -0
  51. package/src/dynamics/git-sim.js +200 -0
  52. package/src/dynamics/layouts.js +112 -0
  53. package/src/elements.js +554 -0
  54. package/src/experiences.js +124 -0
  55. package/src/exploration.js +31 -0
  56. package/src/export/browser.js +53 -0
  57. package/src/export/estudo.js +67 -0
  58. package/src/export/pptx.js +475 -0
  59. package/src/export/roteiro.js +40 -0
  60. package/src/export/shots.js +182 -0
  61. package/src/figures/charts.js +383 -0
  62. package/src/figures/diagrams.js +117 -0
  63. package/src/figures/icons.js +166 -0
  64. package/src/figures/material-pictos.js +20 -0
  65. package/src/figures/pictos.js +255 -0
  66. package/src/figures/points.js +106 -0
  67. package/src/figures/qr.js +29 -0
  68. package/src/figures/ufmap.js +48 -0
  69. package/src/fiscal/autofix.js +377 -0
  70. package/src/fiscal/normalize.js +115 -0
  71. package/src/graph-lab.js +24 -0
  72. package/src/hologram.js +30 -0
  73. package/src/identity.js +86 -0
  74. package/src/import/crop.js +59 -0
  75. package/src/import/index.js +132 -0
  76. package/src/import/legacy-word.js +42 -0
  77. package/src/import/merge.js +45 -0
  78. package/src/import/office.js +123 -0
  79. package/src/import/omml.js +69 -0
  80. package/src/import/pdf-render.js +56 -0
  81. package/src/import/pptx.js +701 -0
  82. package/src/import/xml.js +42 -0
  83. package/src/infographic.js +401 -0
  84. package/src/layouts.js +723 -0
  85. package/src/lessons.js +171 -0
  86. package/src/library.js +399 -0
  87. package/src/markup.js +116 -0
  88. package/src/master.js +214 -0
  89. package/src/mcp/server.js +371 -0
  90. package/src/meeting.js +42 -0
  91. package/src/motion.js +56 -0
  92. package/src/package.js +116 -0
  93. package/src/playground.js +19 -0
  94. package/src/portal-scene.js +20 -0
  95. package/src/preferences.js +61 -0
  96. package/src/protect.js +51 -0
  97. package/src/purpose.js +24 -0
  98. package/src/pytrace.js +1092 -0
  99. package/src/research/duckduckgo.js +73 -0
  100. package/src/research/research.js +202 -0
  101. package/src/research/svg-image.js +17 -0
  102. package/src/research/visuals.js +52 -0
  103. package/src/runtime/api-collection-ui.js +5 -0
  104. package/src/runtime/api-collections.js +28 -0
  105. package/src/runtime/api-core.js +530 -0
  106. package/src/runtime/api-ui.js +966 -0
  107. package/src/runtime/base.css +1774 -0
  108. package/src/runtime/calc.js +139 -0
  109. package/src/runtime/code-lab.js +371 -0
  110. package/src/runtime/decision-lab.js +49 -0
  111. package/src/runtime/diagram.js +341 -0
  112. package/src/runtime/fit.js +268 -0
  113. package/src/runtime/fonts/caveat.css +2 -0
  114. package/src/runtime/fonts/comic-neue.css +3 -0
  115. package/src/runtime/fonts/fredoka.css +2 -0
  116. package/src/runtime/fonts/index.json +10 -0
  117. package/src/runtime/fonts/inter.css +2 -0
  118. package/src/runtime/fonts/patrick-hand.css +2 -0
  119. package/src/runtime/fonts/plus-jakarta-sans.css +2 -0
  120. package/src/runtime/fonts/press-start-2p.css +2 -0
  121. package/src/runtime/fonts/vt323.css +2 -0
  122. package/src/runtime/formula.js +148 -0
  123. package/src/runtime/graph-lab.js +72 -0
  124. package/src/runtime/meeting.css +7 -0
  125. package/src/runtime/meeting.js +10 -0
  126. package/src/runtime/motion.js +15 -0
  127. package/src/runtime/playground.js +11 -0
  128. package/src/runtime/points.js +19 -0
  129. package/src/runtime/portal-scene.css +6 -0
  130. package/src/runtime/portal-scene.js +22 -0
  131. package/src/runtime/runtime.js +827 -0
  132. package/src/runtime/science.js +89 -0
  133. package/src/runtime/skins/aluminio.css +31 -0
  134. package/src/runtime/skins/arcade.css +25 -0
  135. package/src/runtime/skins/aurora.css +17 -0
  136. package/src/runtime/skins/bauhaus.css +19 -0
  137. package/src/runtime/skins/editorial.css +19 -0
  138. package/src/runtime/skins/jornal.css +17 -0
  139. package/src/runtime/skins/manual-noite.css +14 -0
  140. package/src/runtime/skins/manual.css +14 -0
  141. package/src/runtime/skins/noite.css +21 -0
  142. package/src/runtime/skins/oceano.css +17 -0
  143. package/src/runtime/skins/pop.css +23 -0
  144. package/src/runtime/skins/prata.css +18 -0
  145. package/src/runtime/skins/prisma.css +28 -0
  146. package/src/runtime/skins/rabisco.css +18 -0
  147. package/src/runtime/skins/relevo.css +33 -0
  148. package/src/runtime/skins/sinal.css +16 -0
  149. package/src/runtime/skins/terminal.css +23 -0
  150. package/src/runtime/vendor/KATEX-LICENSE.txt +21 -0
  151. package/src/runtime/vendor/MERMAID-LICENSE.txt +21 -0
  152. package/src/runtime/vendor/PLOTLY-LICENSE.txt +21 -0
  153. package/src/runtime/vendor/katex.css +1 -0
  154. package/src/runtime/vendor/mermaid.min.js +3636 -0
  155. package/src/runtime/vendor/plotly.min.js +3620 -0
  156. package/src/runtime/video-player.js +35 -0
  157. package/src/science.js +162 -0
  158. package/src/studio/ai-response.js +36 -0
  159. package/src/studio/api-routes.js +152 -0
  160. package/src/studio/assets/contexto/leia-me.md +12 -0
  161. package/src/studio/assets/contexto/vendas.csv +7 -0
  162. package/src/studio/assets/imagens/colecao-arquitetura.png +0 -0
  163. package/src/studio/assets/imagens/colecao-cor.png +0 -0
  164. package/src/studio/assets/imagens/colecao-equipe.png +0 -0
  165. package/src/studio/assets/imagens/lavanda-cover.jpg +0 -0
  166. package/src/studio/code-routes.js +32 -0
  167. package/src/studio/command-approval.js +48 -0
  168. package/src/studio/demo-decks.js +98 -0
  169. package/src/studio/direction-routes.js +29 -0
  170. package/src/studio/errors.js +65 -0
  171. package/src/studio/exploration-demo.js +17 -0
  172. package/src/studio/exporting.js +105 -0
  173. package/src/studio/generation-report.js +10 -0
  174. package/src/studio/instance.js +48 -0
  175. package/src/studio/layout-samples.js +152 -0
  176. package/src/studio/project.js +371 -0
  177. package/src/studio/public/api-collections.js +28 -0
  178. package/src/studio/public/app.js +5265 -0
  179. package/src/studio/public/art-preview.js +10 -0
  180. package/src/studio/public/calc-fields.js +11 -0
  181. package/src/studio/public/chat-progress.js +47 -0
  182. package/src/studio/public/developer-fields.js +22 -0
  183. package/src/studio/public/explorer.js +443 -0
  184. package/src/studio/public/history.js +58 -0
  185. package/src/studio/public/index.html +867 -0
  186. package/src/studio/public/inspector.js +270 -0
  187. package/src/studio/public/lab-fields.js +5 -0
  188. package/src/studio/public/library.css +275 -0
  189. package/src/studio/public/library.html +55 -0
  190. package/src/studio/public/library.js +471 -0
  191. package/src/studio/public/merge-decks.js +155 -0
  192. package/src/studio/public/review-ui.js +100 -0
  193. package/src/studio/public/screenshot-editor.js +140 -0
  194. package/src/studio/public/share-ui.js +72 -0
  195. package/src/studio/public/slide-clipboard.js +23 -0
  196. package/src/studio/public/slide-form.js +1263 -0
  197. package/src/studio/public/studio-awareness.js +154 -0
  198. package/src/studio/public/studio-next.css +303 -0
  199. package/src/studio/public/style.css +1262 -0
  200. package/src/studio/public/ui-icons.js +2 -0
  201. package/src/studio/public/viewers.js +372 -0
  202. package/src/studio/public/visual-editor.js +326 -0
  203. package/src/studio/public/workspace.js +18 -0
  204. package/src/studio/public-files.js +1 -0
  205. package/src/studio/request-helpers.js +41 -0
  206. package/src/studio/server.js +1583 -0
  207. package/src/studio/share-routes.js +146 -0
  208. package/src/studio/slide-copy-routes.js +26 -0
  209. package/src/studio/slide-copy.js +30 -0
  210. package/src/studio/snapshot.js +160 -0
  211. package/src/studio/style-routes.js +103 -0
  212. package/src/studio/template-collections.js +97 -0
  213. package/src/studio/versions.js +95 -0
  214. package/src/studio/video-download.js +29 -0
  215. package/src/studio/visual-keys.js +52 -0
  216. package/src/studio/workspaces.js +39 -0
  217. package/src/table.js +93 -0
  218. package/src/templates/scaffold.js +372 -0
  219. package/src/themes.js +604 -0
  220. package/src/trace-view.js +450 -0
  221. package/src/uid.js +19 -0
  222. package/src/video-player.js +40 -0
  223. package/src/visual-edits.js +99 -0
  224. package/src/ws.js +134 -0
  225. package/templates/cenario/Texto no cen/303/241rio.yaml" +171 -0
  226. package/templates/cenario/imagens/cidade.svg +30 -0
  227. package/templates/cenario/imagens/pessoa.svg +15 -0
  228. package/templates/cenario-e-ciencia.yaml +47 -0
  229. package/templates/ensaio-api.yaml +160 -0
  230. package/templates/exemplo-alegre.yaml +75 -0
  231. package/templates/exemplo-keynote.yaml +90 -0
  232. package/templates/exemplo-napkin.yaml +139 -0
  233. package/templates/exemplo.yaml +228 -0
package/src/ws.js ADDED
@@ -0,0 +1,134 @@
1
+ // WebSocket mínimo (RFC 6455) sem dependências: cliente (Studio → serviço de conversa em tempo real) e o
2
+ // lado servidor (usado pela API de mentira). Feito à mão para aceitar cabeçalhos (token) e o certificado
3
+ // da empresa (ca), que o WebSocket do navegador/Node não deixam configurar.
4
+ import crypto from "node:crypto";
5
+ import net from "node:net";
6
+ import tls from "node:tls";
7
+ import { EventEmitter } from "node:events";
8
+
9
+ const GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
10
+ const accept = (key) => crypto.createHash("sha1").update(key + GUID).digest("base64");
11
+
12
+ // ---------- quadros ----------
13
+ function encode(data, { opcode, mask }) {
14
+ const payload = Buffer.isBuffer(data) ? data : Buffer.from(String(data), "utf8");
15
+ const op = opcode ?? (Buffer.isBuffer(data) ? 0x2 : 0x1);
16
+ const len = payload.length;
17
+ const head = [0x80 | op];
18
+ let ext = Buffer.alloc(0);
19
+ if (len < 126) head.push((mask ? 0x80 : 0) | len);
20
+ else if (len < 65536) { head.push((mask ? 0x80 : 0) | 126); ext = Buffer.alloc(2); ext.writeUInt16BE(len); }
21
+ else { head.push((mask ? 0x80 : 0) | 127); ext = Buffer.alloc(8); ext.writeBigUInt64BE(BigInt(len)); }
22
+ if (!mask) return Buffer.concat([Buffer.from(head), ext, payload]);
23
+ const key = crypto.randomBytes(4);
24
+ const masked = Buffer.alloc(len);
25
+ for (let i = 0; i < len; i++) masked[i] = payload[i] ^ key[i & 3];
26
+ return Buffer.concat([Buffer.from(head), ext, key, masked]);
27
+ }
28
+
29
+ // Conexão já estabelecida (depois do handshake), dos dois lados.
30
+ class Conn extends EventEmitter {
31
+ constructor(socket, { client }) {
32
+ super();
33
+ this.socket = socket;
34
+ this.client = client; // cliente mascara o que envia
35
+ this.buf = Buffer.alloc(0);
36
+ this.parts = null; // mensagem fragmentada em andamento
37
+ this.open = true;
38
+ socket.on("data", (d) => { this.buf = Buffer.concat([this.buf, d]); this.parse(); });
39
+ socket.on("close", () => { if (this.open) { this.open = false; this.emit("close", 1006, "conexão caiu"); } });
40
+ // conexão derrubada do outro lado (ECONNRESET…): vira "close", nunca um erro solto que derruba o Studio
41
+ socket.on("error", (e) => {
42
+ if (this.listenerCount("error")) this.emit("error", e);
43
+ if (this.open) { this.open = false; this.emit("close", 1006, e.message); }
44
+ });
45
+ }
46
+ parse() {
47
+ for (;;) {
48
+ if (this.buf.length < 2) return;
49
+ const b0 = this.buf[0], b1 = this.buf[1];
50
+ const fin = !!(b0 & 0x80), op = b0 & 0x0f, masked = !!(b1 & 0x80);
51
+ let len = b1 & 0x7f, off = 2;
52
+ if (len === 126) { if (this.buf.length < 4) return; len = this.buf.readUInt16BE(2); off = 4; }
53
+ else if (len === 127) { if (this.buf.length < 10) return; len = Number(this.buf.readBigUInt64BE(2)); off = 10; }
54
+ const need = off + (masked ? 4 : 0) + len;
55
+ if (this.buf.length < need) return;
56
+ let payload = this.buf.subarray(off + (masked ? 4 : 0), need);
57
+ if (masked) { const k = this.buf.subarray(off, off + 4); payload = Buffer.from(payload.map((x, i) => x ^ k[i & 3])); }
58
+ this.buf = this.buf.subarray(need);
59
+ if (op === 0x8) { // close
60
+ const code = payload.length >= 2 ? payload.readUInt16BE(0) : 1005;
61
+ if (this.open) { this.open = false; try { this.socket.write(encode(payload.subarray(0, 2), { opcode: 0x8, mask: this.client })); } catch {} this.socket.end(); this.emit("close", code, payload.subarray(2).toString()); }
62
+ return;
63
+ }
64
+ if (op === 0x9) { this.socket.write(encode(payload, { opcode: 0xa, mask: this.client })); continue; } // ping → pong
65
+ if (op === 0xa) continue;
66
+ if (op === 0x0) { if (!this.parts) continue; this.parts.chunks.push(payload); }
67
+ else this.parts = { op, chunks: [payload] };
68
+ if (fin && this.parts) {
69
+ const all = Buffer.concat(this.parts.chunks), isText = this.parts.op === 0x1;
70
+ this.parts = null;
71
+ this.emit("message", isText ? all.toString("utf8") : all, isText);
72
+ }
73
+ }
74
+ }
75
+ send(data) { if (this.open) this.socket.write(encode(data, { mask: this.client })); }
76
+ close(code = 1000) {
77
+ if (!this.open) return;
78
+ const p = Buffer.alloc(2); p.writeUInt16BE(code);
79
+ try { this.socket.write(encode(p, { opcode: 0x8, mask: this.client })); } catch {}
80
+ this.open = false;
81
+ setTimeout(() => this.socket.destroy(), 200);
82
+ this.emit("close", code, "");
83
+ }
84
+ }
85
+
86
+ // Cliente: ws:// ou wss://, com cabeçalhos e certificado da empresa.
87
+ export function connectWs(url, { headers = {}, ca, insecure = false, timeout = 15000, protocols } = {}) {
88
+ return new Promise((resolve, reject) => {
89
+ let u;
90
+ try { u = new URL(url); } catch { reject(Object.assign(new Error(`Endereço inválido: ${url}`), { kind: "config" })); return; }
91
+ if (!/^wss?:$/.test(u.protocol)) { reject(Object.assign(new Error(`Conversa em tempo real precisa de ws:// ou wss:// (veio ${u.protocol})`), { kind: "config" })); return; }
92
+ const secure = u.protocol === "wss:";
93
+ const port = Number(u.port) || (secure ? 443 : 80);
94
+ const key = crypto.randomBytes(16).toString("base64");
95
+ const opts = { host: u.hostname, port, servername: u.hostname, ca, rejectUnauthorized: !insecure };
96
+ const socket = secure ? tls.connect(opts) : net.connect(opts);
97
+ const timer = setTimeout(() => { socket.destroy(); reject(Object.assign(new Error(`sem resposta de ${u.host} em ${Math.round(timeout / 1000)}s`), { code: "TIMEOUT" })); }, timeout);
98
+ socket.once("error", (e) => { clearTimeout(timer); reject(e); });
99
+ socket.once(secure ? "secureConnect" : "connect", () => {
100
+ const lines = [`GET ${u.pathname}${u.search} HTTP/1.1`, `Host: ${u.host}`, "Upgrade: websocket", "Connection: Upgrade",
101
+ `Sec-WebSocket-Key: ${key}`, "Sec-WebSocket-Version: 13", ...(protocols ? [`Sec-WebSocket-Protocol: ${[].concat(protocols).join(", ")}`] : []),
102
+ ...Object.entries(headers).map(([k, v]) => `${k}: ${v}`)];
103
+ socket.write(lines.join("\r\n") + "\r\n\r\n");
104
+ });
105
+ let head = Buffer.alloc(0);
106
+ const onData = (d) => {
107
+ head = Buffer.concat([head, d]);
108
+ const end = head.indexOf("\r\n\r\n");
109
+ if (end < 0) return;
110
+ socket.removeListener("data", onData);
111
+ clearTimeout(timer);
112
+ const text = head.subarray(0, end).toString();
113
+ const status = Number((text.match(/^HTTP\/1\.1 (\d+)/) || [])[1]);
114
+ if (status !== 101 || !text.toLowerCase().includes(`sec-websocket-accept: ${accept(key).toLowerCase()}`)) {
115
+ socket.destroy();
116
+ const body = head.subarray(end + 4).toString().slice(0, 400);
117
+ reject(Object.assign(new Error(`o serviço recusou a conexão (HTTP ${status || "?"})${body ? ": " + body : ""}`), { status }));
118
+ return;
119
+ }
120
+ const conn = new Conn(socket, { client: true });
121
+ const rest = head.subarray(end + 4);
122
+ resolve(conn);
123
+ if (rest.length) { conn.buf = rest; conn.parse(); }
124
+ };
125
+ socket.on("data", onData);
126
+ });
127
+ }
128
+
129
+ // Servidor: responde ao "upgrade" de um http.Server e devolve a conexão (usado pela API de mentira).
130
+ export function acceptWs(req, socket) {
131
+ const key = req.headers["sec-websocket-key"];
132
+ socket.write(["HTTP/1.1 101 Switching Protocols", "Upgrade: websocket", "Connection: Upgrade", `Sec-WebSocket-Accept: ${accept(key)}`].join("\r\n") + "\r\n\r\n");
133
+ return new Conn(socket, { client: false });
134
+ }
@@ -0,0 +1,171 @@
1
+ # Demonstração do "Texto no cenário" (layout scenography): todas as composições e tudo o que dá para ajustar.
2
+ # Biblioteca: Nova, "Exemplo: texto no cenário". As imagens de exemplo estão em imagens/ (troque pelas suas).
3
+ title: Texto no cenário
4
+ theme: aurora
5
+ motion: none
6
+ author: Seu nome
7
+ duration: 15
8
+ slides:
9
+ - layout: scenography
10
+ scene: stage
11
+ kicker: DEMONSTRAÇÃO
12
+ title: "TEXTO NO\nCENÁRIO"
13
+ subtitle: Treze composições e tudo o que dá para ajustar.
14
+ caption: SAGADECK / TEXTO NO CENÁRIO
15
+ notes: Cada slide deste deck mostra uma composição (campo scene) ou uma opção. Abra o painel Formatar para ver os campos.
16
+
17
+ - layout: section
18
+ title: As composições
19
+ subtitle: Campo "Composição" (scene). O texto continua editável em todas.
20
+
21
+ - layout: scenography
22
+ scene: stage
23
+ kicker: "scene: stage"
24
+ title: "ALÉM DO\nÓBVIO"
25
+ subtitle: Palco e profundidade. Letras monumentais atrás de uma escultura.
26
+ caption: PALCO E PROFUNDIDADE
27
+
28
+ - layout: scenography
29
+ scene: floor
30
+ kicker: "scene: floor"
31
+ title: "NOVOS\nCAMINHOS"
32
+ caption: CHÃO EM PERSPECTIVA
33
+
34
+ - layout: scenography
35
+ scene: signs
36
+ kicker: "scene: signs"
37
+ title: "IDEIAS\nEM CENA"
38
+ subtitle: Uma placa na cidade.
39
+ caption: PLACAS NA CIDADE
40
+
41
+ - layout: scenography
42
+ scene: terminal
43
+ kicker: ./acesso --scene terminal
44
+ title: "acesso\nconcedido"
45
+ subtitle: Segurança começa pela curiosidade.
46
+ caption: TERMINAL HACKER
47
+
48
+ - layout: scenography
49
+ scene: cafe
50
+ kicker: "Hoje no cardápio (scene: cafe)"
51
+ title: "Ideias coadas\nna hora"
52
+ subtitle: Com calma, açúcar a gosto.
53
+ caption: LOUSA DE CAFÉ
54
+
55
+ - layout: scenography
56
+ scene: travel
57
+ kicker: "EMBARQUE IMEDIATO / scene: travel"
58
+ title: "PRÓXIMO\nDESTINO"
59
+ subtitle: O plano para os próximos 12 meses.
60
+ caption: CARTÃO DE EMBARQUE
61
+
62
+ - layout: scenography
63
+ scene: ticker
64
+ kicker: "Q3 2026 / scene: ticker"
65
+ title: "RESULTADO\nRECORDE"
66
+ subtitle: Receita 38% acima do ano passado.
67
+ caption: PREGÃO FINANCEIRO
68
+
69
+ - layout: scenography
70
+ scene: marquee
71
+ kicker: "EM CARTAZ / scene: marquee"
72
+ title: "HOJE:\nA ESTREIA"
73
+ subtitle: Sessão única, entrada franca.
74
+ caption: LETREIRO DE CINEMA
75
+
76
+ - layout: scenography
77
+ scene: blueprint
78
+ kicker: "scene: blueprint"
79
+ title: "PROJETO\nDO FUTURO"
80
+ subtitle: medidas em ideias, escala 1:1
81
+ caption: PLANTA TÉCNICA
82
+
83
+ - layout: scenography
84
+ scene: magazine
85
+ kicker: "CAPA / scene: magazine"
86
+ title: "O ANO DA\nVIRADA"
87
+ subtitle: Como uma equipe pequena mudou o jogo.
88
+ caption: CAPA DE REVISTA
89
+
90
+ - layout: scenography
91
+ scene: orbit
92
+ kicker: "scene: orbit"
93
+ title: "MISSÃO\nCUMPRIDA"
94
+ subtitle: Da ideia à órbita em seis meses.
95
+ caption: ÓRBITA
96
+
97
+ - layout: scenography
98
+ scene: synthwave
99
+ kicker: "scene: synthwave"
100
+ title: "DE VOLTA\nAO FUTURO"
101
+ subtitle: As ideias que voltaram com tudo.
102
+ caption: NEON ANOS 80
103
+
104
+ - layout: scenography
105
+ scene: gallery
106
+ kicker: "scene: gallery"
107
+ title: "Menos\né mais"
108
+ subtitle: Uma ideia por parede.
109
+ caption: PAREDE DE GALERIA
110
+
111
+ - layout: section
112
+ title: E dá para ajustar
113
+ subtitle: Imagem de fundo, transparência, recorte na frente das letras e tamanho do texto.
114
+
115
+ - layout: scenography
116
+ scene: stage
117
+ image: imagens/cidade.svg
118
+ imageOpacity: 1
119
+ kicker: "image: imagens/cidade.svg"
120
+ title: "IMAGEM DE\nFUNDO"
121
+ subtitle: "Imagem de fundo (image), sem transparência: imageOpacity: 1"
122
+ caption: IMAGEM DE FUNDO
123
+ notes: Troque imagens/cidade.svg por uma foto sua (arquivo ao lado do deck ou link).
124
+
125
+ - layout: scenography
126
+ scene: stage
127
+ image: imagens/cidade.svg
128
+ imageOpacity: 0.3
129
+ kicker: "imageOpacity: 0.3"
130
+ title: "MAIS\nTRANSPARENTE"
131
+ subtitle: De 0 (some) a 1 (inteira). Sem o campo, fica em 0.85.
132
+ caption: TRANSPARÊNCIA DO FUNDO
133
+
134
+ - layout: scenography
135
+ scene: floor
136
+ foreground: imagens/pessoa.svg
137
+ kicker: "foreground: imagens/pessoa.svg"
138
+ title: "NA FRENTE\nDAS LETRAS"
139
+ caption: RECORTE EM PRIMEIRO PLANO
140
+ notes: O recorte (PNG ou SVG com fundo transparente, do tamanho do slide) fica por cima do texto. O fundo não é recortado sozinho; recorte a pessoa num editor.
141
+
142
+ - layout: scenography
143
+ scene: gallery
144
+ foreground: imagens/pessoa.svg
145
+ kicker: "foreground + gallery"
146
+ title: "Olhe de\nperto"
147
+ subtitle: Alguém parado diante da parede.
148
+ caption: RECORTE NA GALERIA
149
+
150
+ - layout: scenography
151
+ scene: stage
152
+ image: imagens/cidade.svg
153
+ imageOpacity: 0.6
154
+ foreground: imagens/pessoa.svg
155
+ titleSize: 300
156
+ kicker: "titleSize: 300"
157
+ title: "TUDO\nJUNTO"
158
+ subtitle: Fundo, transparência, recorte e texto maior.
159
+ caption: TUDO JUNTO
160
+
161
+ - layout: scenography
162
+ scene: orbit
163
+ titleSize: 110
164
+ kicker: "titleSize: 110"
165
+ title: "Texto menor, mais respiro"
166
+ subtitle: Sem titleSize, cada composição usa o seu tamanho padrão.
167
+ caption: TAMANHO DO TEXTO
168
+
169
+ - layout: end
170
+ title: Agora é com você
171
+ subtitle: Inserir, Texto no cenário. Depois é só escolher a composição.
@@ -0,0 +1,30 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080" width="1920" height="1080">
2
+ <!-- fundo de exemplo do deck "Texto no cenário": uma cidade ao entardecer (troque por uma foto sua) -->
3
+ <defs>
4
+ <linearGradient id="ceu" x1="0" y1="0" x2="0" y2="1">
5
+ <stop offset="0" stop-color="#241a4f"/>
6
+ <stop offset=".55" stop-color="#b8517a"/>
7
+ <stop offset=".8" stop-color="#ffb070"/>
8
+ </linearGradient>
9
+ <pattern id="janelas" width="36" height="44" patternUnits="userSpaceOnUse">
10
+ <rect x="8" y="10" width="14" height="18" fill="#ffd98a" opacity=".75"/>
11
+ </pattern>
12
+ </defs>
13
+ <rect width="1920" height="1080" fill="url(#ceu)"/>
14
+ <circle cx="1380" cy="700" r="170" fill="#ffe2a6" opacity=".9"/>
15
+ <g fill="#3a2350">
16
+ <rect x="0" y="640" width="220" height="440"/><rect x="240" y="520" width="170" height="560"/>
17
+ <rect x="430" y="700" width="260" height="380"/><rect x="700" y="430" width="150" height="650"/>
18
+ <rect x="870" y="610" width="230" height="470"/><rect x="1120" y="540" width="190" height="540"/>
19
+ <rect x="1330" y="760" width="210" height="320"/><rect x="1560" y="480" width="160" height="600"/>
20
+ <rect x="1740" y="660" width="180" height="420"/>
21
+ </g>
22
+ <g fill="#1d1230">
23
+ <rect x="100" y="780" width="260" height="300"/><rect x="560" y="820" width="210" height="260"/>
24
+ <rect x="980" y="760" width="240" height="320"/><rect x="1450" y="840" width="300" height="240"/>
25
+ </g>
26
+ <g fill="url(#janelas)">
27
+ <rect x="240" y="520" width="170" height="560"/><rect x="700" y="430" width="150" height="650"/>
28
+ <rect x="1120" y="540" width="190" height="540"/><rect x="1560" y="480" width="160" height="600"/>
29
+ </g>
30
+ </svg>
@@ -0,0 +1,15 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080" width="1920" height="1080">
2
+ <!-- recorte de exemplo (fundo transparente): uma pessoa em pé, à direita. Fica na frente das letras (foreground).
3
+ Para uma foto sua, recorte a pessoa num editor e salve como PNG transparente do mesmo tamanho do slide. -->
4
+ <defs>
5
+ <linearGradient id="luz" x1="0" y1="0" x2="1" y2="0">
6
+ <stop offset="0" stop-color="#2a2238"/>
7
+ <stop offset=".75" stop-color="#1a1424"/>
8
+ <stop offset="1" stop-color="#ff9a6b"/>
9
+ </linearGradient>
10
+ </defs>
11
+ <g fill="url(#luz)">
12
+ <ellipse cx="1470" cy="455" rx="62" ry="74"/>
13
+ <path d="M1452 520h40l10 30c70 10 118 40 130 110l40 250c6 40-40 50-52 12l-40-190-10 398h-68l-20-300-20 300h-68l-12-398-40 190c-12 38-58 28-52-12l40-250c12-70 60-100 122-110z"/>
14
+ </g>
15
+ </svg>
@@ -0,0 +1,47 @@
1
+ title: Texto no cenário e matemática
2
+ id: cenario-e-ciencia
3
+ theme: aurora
4
+ motion: none
5
+ slides:
6
+ - layout: scenography
7
+ scene: stage
8
+ kicker: IDEIAS QUE OCUPAM ESPAÇO
9
+ title: "ALÉM DO\nÓBVIO"
10
+ subtitle: O texto também faz parte da história.
11
+ caption: SAGADECK / ESTUDO 01
12
+ deco: none
13
+ - layout: scenography
14
+ scene: floor
15
+ kicker: UMA NOVA PERSPECTIVA
16
+ title: "NOVOS\nCAMINHOS"
17
+ caption: SAGADECK / ESTUDO 02
18
+ deco: none
19
+ - layout: scenography
20
+ scene: signs
21
+ kicker: PRÓXIMA PARADA
22
+ title: "IDEIAS\nEM CENA"
23
+ subtitle: Mensagens que pertencem ao lugar.
24
+ caption: SAGADECK / ESTUDO 03
25
+ deco: none
26
+ - layout: science
27
+ title: A onda e sua derivada
28
+ equations:
29
+ - label: Função
30
+ latex: 'f(x)=\sin(x)'
31
+ - label: Derivada
32
+ latex: 'f\prime(x)=\cos(x)'
33
+ - label: Identidade
34
+ latex: '\sin^2(x)+\cos^2(x)=1'
35
+ plot:
36
+ preset: wave
37
+ notes: Arraste uma área do gráfico para dar zoom. Passe o mouse para consultar os valores.
38
+ - layout: science
39
+ title: Matemática que você pode explorar
40
+ equations:
41
+ - label: Raio
42
+ latex: 'r=\sqrt{x^2+y^2}'
43
+ - label: Superfície
44
+ latex: 'z=\sin(r)'
45
+ plot:
46
+ preset: surface
47
+ notes: Arraste para girar. Use a roda do mouse para aproximar.
@@ -0,0 +1,160 @@
1
+ # Ensaio de aula de APIs de IA: roda contra a API de mentira, no ambiente embutido ENSAIO do Studio
2
+ # (biblioteca → Nova → "Exemplo: aula de APIs ao vivo", ou `sagadeck ensaio-api`).
3
+ # Serve de modelo: troque as URLs e os caminhos $.… pelos do seu serviço e cadastre os seus ambientes
4
+ # no Studio (Inserir → Ambientes), que grava em ~/.sagadeck/ambientes.yaml. Veja "Slide api" em docs/REFERENCIA.md.
5
+ title: "Ensaio: APIs de IA ao vivo"
6
+ theme: sinal
7
+ author: Seu nome
8
+ duration: 30
9
+ slides:
10
+ - layout: cover
11
+ kicker: Ensaio
12
+ title: APIs de IA, ==ao vivo==
13
+ subtitle: Do token à resposta, executando na frente de todo mundo
14
+ notes: |
15
+ Este deck roda contra uma API de mentira (o ambiente ENSAIO, que o Studio sobe sozinho). Apresente e clique em Executar em cada slide.
16
+ Se você já tem ambientes seus, clique no selo do slide (DEV, HOM…) e escolha ENSAIO.
17
+ Tudo funciona igual com o serviço de verdade: troque os endereços em Inserir → Ambientes.
18
+
19
+ - layout: api
20
+ id: identity
21
+ kicker: Passo 1 · Identity
22
+ title: Primeiro, o ==token==
23
+ text: Toda chamada leva um JWT que vale 30 minutos
24
+ request:
25
+ method: POST
26
+ url: "{{identity}}"
27
+ auth: false
28
+ body: { client_id: "{{client_id}}", client_secret: "{{secret.client_secret}}" }
29
+ token: "$.data.token"
30
+ notes: |
31
+ Mostre o corpo: o client_secret aparece como {{secret.client_secret}} — o valor fica no ambiente, nunca no slide.
32
+ Execute: o JWT aparece decodificado, com a contagem regressiva. Daqui para frente, todo slide usa este token (olhe o final ••••).
33
+
34
+ - layout: api
35
+ id: llm
36
+ kicker: Passo 2 · LLM
37
+ title: A pergunta mais ==simples==
38
+ request:
39
+ method: POST
40
+ url: "{{base}}/sync"
41
+ body: { messages: [ { role: user, content: "O que é RAG, em uma frase?" } ] }
42
+ answer: "$.choices[0].message.content"
43
+ notes: Edite a pergunta na hora (aba Corpo) e execute de novo. Mostre as abas curl e Python.
44
+
45
+ - layout: api
46
+ id: openrouter-nemotron
47
+ kicker: OpenRouter (real)
48
+ title: Pergunte ao ==Nemotron==
49
+ text: Chamada real ao modelo gratuito NVIDIA Nemotron pelo OpenRouter
50
+ request:
51
+ method: POST
52
+ url: "{{base}}/chat/completions"
53
+ auth: false
54
+ headers:
55
+ Authorization: "Bearer {{secret.openrouter_api_key}}"
56
+ X-Title: SagaDeck
57
+ body:
58
+ model: nvidia/nemotron-3-super-120b-a12b:free
59
+ max_tokens: 350
60
+ messages:
61
+ - role: user
62
+ content: "Explique o que é uma API em uma frase, em português."
63
+ answer: "$.choices[0].message.content"
64
+ notes: |
65
+ Esta chamada acessa o OpenRouter de verdade com um modelo gratuito compatível com Chat Completions.
66
+ No selo de ambiente, escolha OPENROUTER.
67
+ A chave não fica no deck: defina OPENROUTER_API_KEY no processo que inicia o Studio e reinicie-o.
68
+ Edite a pergunta na aba Corpo e execute novamente para testar o comportamento do modelo.
69
+
70
+ - layout: api
71
+ id: workflow
72
+ kicker: Passo 3 · Workflow
73
+ title: Inicia e ==acompanha== até terminar
74
+ text: O início devolve só o código da execução; a consulta repete até FINISHED
75
+ mode: polling
76
+ tab: python-comentado
77
+ request: { url: "{{base}}/start", body: { workflow: "{{wf}}", input: { path_id: "store/contrato.txt" } } }
78
+ polling: { id: "$.executionId", check: { url: "{{base}}/status/{{id}}" }, status: "$.status", done: [FINISHED], failed: [ERROR], interval: 0.8 }
79
+ steps: "$.responses"
80
+ stepText: "$.output"
81
+ notes: Deixe na aba Python comentado e execute — o laço while acende a cada consulta, enquanto a linha do tempo cresce.
82
+
83
+ - layout: api
84
+ id: stream
85
+ kicker: Passo 4 · Streaming
86
+ title: A resposta chega ==aos poucos==
87
+ mode: stream
88
+ request: { method: POST, url: "{{base}}/stream", body: { stream: true } }
89
+ notes: "Compare com o síncrono: aqui o texto aparece enquanto é gerado."
90
+
91
+ - layout: api
92
+ id: upload
93
+ kicker: Passo 5 · FileManager
94
+ title: Sobe o arquivo, volta o ==path_id==
95
+ file: contrato.txt
96
+ request: { url: "{{base}}/upload", form: { file: "@file", pasta: workshop } }
97
+ save: { path_id: "$.path_id" }
98
+ notes: Arraste outro arquivo no slide se quiser. O path_id fica guardado para os próximos slides.
99
+
100
+ - layout: api
101
+ id: ocr
102
+ kicker: Passo 6 · OCR
103
+ title: Lendo pelo ==path_id==
104
+ request: { url: "{{base}}/ocr", body: { path_id: "{{path_id}}" } }
105
+ answer: "$.text"
106
+ notes: "Mostre que {{path_id}} veio do slide anterior (aba curl: já com o valor)."
107
+
108
+ - layout: api
109
+ id: indexador
110
+ kicker: Passo 7 · Indexador
111
+ title: Planilha ==linha a linha==
112
+ tab: fields
113
+ request: { url: "{{base}}/index", body: { path_id: "{{path_id}}", mode: rows, sheet: { header_row: 1 }, chunk_size: 0 } }
114
+ fields:
115
+ "$.mode": "rows: cada linha vira um documento; pdf: o arquivo inteiro, em pedaços"
116
+ "$.sheet.header_row": "linha do cabeçalho (começa em 1): as colunas viram metadados"
117
+ "$.chunk_size": "com rows, tem que ser 0 — qualquer outro valor faz a indexação falhar"
118
+ "$.path_id": "o que o FileManager devolveu"
119
+ answer: "$.documents"
120
+ notes: "Mude chunk_size para 800 na aba Corpo e execute: a indexação falha. É a combinação que a documentação não conta."
121
+
122
+ - layout: api
123
+ id: embeddings
124
+ kicker: Passo 8 · Embeddings
125
+ title: Qual frase fica ==mais perto==?
126
+ request: { url: "{{base}}/embeddings", body: { model: emb, input: "{{text}}" } }
127
+ similarity:
128
+ reference: Quero abrir uma conta no banco
129
+ texts: [ "Vai chover amanhã em São Paulo?", "Como faço para abrir uma conta?", "Abrir conta no banco hoje" ]
130
+ notes: "Peça frases para a plateia e escreva na aba Frases."
131
+
132
+ - layout: api
133
+ id: tts
134
+ kicker: Passo 9 · Voz
135
+ title: Texto que ==fala==
136
+ audio: fala.wav
137
+ request: { url: "{{base}}/tts", body: { text: "Bom dia, pessoal" } }
138
+
139
+ - layout: api
140
+ id: stt
141
+ kicker: Passo 10 · Escuta
142
+ title: Fala que vira ==texto==
143
+ mic: true
144
+ request: { url: "{{base}}/stt", form: { audio: "@file", idioma: pt-BR } }
145
+ answer: "$.text"
146
+ notes: "Clique em Gravar, fale, clique em Parar: ele envia sozinho."
147
+
148
+ - layout: api
149
+ id: tempo-real
150
+ kicker: Passo 11 · Tempo real
151
+ title: Conversa por ==voz==, ao vivo
152
+ mode: realtime
153
+ realtime:
154
+ url: "{{ws}}/realtime"
155
+ open: [ { type: session.update, session: { voice: alloy, instructions: "Responda em português, curto." } } ]
156
+ notes: "Conecte, clique em Falar, fale e clique em Parar. Mostre a aba Mensagens: cada evento do WebSocket, nos dois sentidos."
157
+
158
+ - layout: end
159
+ title: Obrigado.
160
+ subtitle: Perguntas?
@@ -0,0 +1,75 @@
1
+ title: Apresentação Alegre e Visual
2
+ theme: rabisco
3
+ duration: 15
4
+ slides:
5
+ - layout: cover
6
+ kicker: Ideias Vivas · Sem Sono
7
+ title: Como Criar Slides Bonitinhos & Visuais
8
+ subtitle: Menos texto longo, muito mais impacto e cores alegres
9
+ author: SagaDeck Studio
10
+ - layout: stats
11
+ kicker: Métricas em Destaque
12
+ title: O Poder dos Números Visuais
13
+ stats:
14
+ - value: 98.7%
15
+ label: Retenção da Atenção
16
+ trend: +34%
17
+ trendUp: true
18
+ icon: heart
19
+ text: Público conectado do início ao fim
20
+ - value: 4.8x
21
+ label: Mais Rápido de Ler
22
+ trend: recorde
23
+ trendUp: true
24
+ icon: zap
25
+ text: Zero cansaço visual
26
+ - value: 2.100+
27
+ label: Ícones Disponíveis
28
+ trend: ilimitado
29
+ trendUp: true
30
+ icon: sparkles
31
+ text: Elementos gráficos prontos
32
+ - layout: steps
33
+ kicker: Fluxo Visual
34
+ title: Processo Simples em 3 Etapas
35
+ steps:
36
+ - stepNum: 1
37
+ title: Rascunho
38
+ text: Escolha o tema Rabisco ou Oceano
39
+ icon: pen-tool
40
+ tag: 1 Minuto
41
+ - stepNum: 2
42
+ title: Visualizar
43
+ text: Troque parágrafos por cards e métricas
44
+ icon: layout-grid
45
+ tag: Auto-Fit
46
+ - stepNum: 3
47
+ title: Apresentar
48
+ text: Entregue um show no palco sem sono
49
+ icon: smile
50
+ tag: Aplausos
51
+ - layout: cards
52
+ kicker: Cartões Inteligentes
53
+ title: Widgets que Eliminam Textão
54
+ cols: 3
55
+ items:
56
+ - icon: check-circle-2
57
+ badge: Recomendado
58
+ title: Checklist Visual
59
+ text: Substitui listas sem graça por confirmações visuais.
60
+ check: true
61
+ checkText: Pronto para uso
62
+ - icon: target
63
+ title: Meta de Conclusão
64
+ text: Progresso visual fácil de acompanhar.
65
+ progress: 88
66
+ progressLabel: Meta Atingida
67
+ - icon: award
68
+ title: Avaliação do Público
69
+ text: Nota máxima dada pela audiência.
70
+ rating: 5
71
+ ratingLabel: 5.0 no G2
72
+ tags:
73
+ - Alegre
74
+ - Dinâmico
75
+ - Sem Sono