primocode 8.42.1 → 9.0.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.
- package/README.md +41 -37
- package/bin/primocode.js +599 -327
- package/lib/acervo.js +8 -1
- package/lib/act.js +205 -114
- package/lib/api.js +35 -4
- package/lib/boas-vindas.js +31 -192
- package/lib/catalogo.js +60 -60
- package/lib/config.js +1 -1
- package/lib/conta.js +3 -24
- package/lib/diff.js +161 -0
- package/lib/diretor.js +37 -47
- package/lib/entrada.js +545 -0
- package/lib/especialistas.js +2 -2
- package/lib/estudio/assets.js +343 -0
- package/lib/estudio/identidade.js +560 -0
- package/lib/estudio/index.js +565 -0
- package/lib/estudio/plano.js +327 -0
- package/lib/estudio/projeto.js +246 -0
- package/lib/estudio/remotion.js +606 -0
- package/lib/estudio/slides.js +190 -0
- package/lib/estudio/video.js +296 -0
- package/lib/fala.js +13 -1
- package/lib/marca.js +4 -1
- package/lib/marketplace.js +189 -0
- package/lib/permissao.js +137 -0
- package/lib/registro.js +229 -0
- package/lib/skills.js +329 -0
- package/lib/tools.js +51 -181
- package/lib/ui.js +7 -3
- package/lib/voz.js +239 -0
- package/package.json +12 -3
- package/skills/acessibilidade/SKILL.md +28 -0
- package/skills/api-que-nao-quebra/SKILL.md +27 -0
- package/skills/depurar-de-verdade/SKILL.md +29 -0
- package/skills/editar-meu-video/SKILL.md +59 -0
- package/skills/escrever-em-portugues/SKILL.md +28 -0
- package/skills/git-limpo/SKILL.md +28 -0
- package/skills/motion-de-primeira/SKILL.md +62 -0
- package/skills/pagina-que-converte/SKILL.md +28 -0
- package/skills/performance-web/SKILL.md +28 -0
- package/skills/revisao-antes-de-entregar/SKILL.md +27 -0
- package/skills/slides-que-prendem/SKILL.md +40 -0
- package/studio/edge.py +16 -66
- package/studio/narrar.py +274 -0
- package/studio/pessoa.py +167 -0
- package/voz/primo_voz/__init__.py +0 -0
- package/voz/primo_voz/__main__.py +325 -0
- package/voz/primo_voz/escuta.py +235 -0
- package/voz/primo_voz/orbe.py +216 -0
- package/lib/audio-livre.js +0 -177
- package/lib/chaves.js +0 -149
- package/lib/claude-engine.js +0 -631
- package/lib/codex-engine.js +0 -208
- package/lib/remotion.js +0 -663
- package/lib/studio.js +0 -960
- package/studio/PRIMOCODE.md +0 -58
- package/studio/README.md +0 -154
- package/studio/__pycache__/edge.cpython-311.pyc +0 -0
- package/studio/__pycache__/elevenlabs.cpython-311.pyc +0 -0
- package/studio/__pycache__/voz.cpython-311.pyc +0 -0
- package/studio/arquivos/corte-teste-de-camera-fb823.json +0 -57
- package/studio/ferramentas/00-protocolo.md +0 -125
- package/studio/ferramentas/01-modelos.md +0 -270
- package/studio/ferramentas/README.md +0 -32
- package/studio/ferramentas/corte.md +0 -919
- package/studio/ferramentas/grade.md +0 -92
- package/studio/ferramentas/prisma.md +0 -107
- package/studio/ferramentas/prosa.md +0 -86
- package/studio/ferramentas/tela.md +0 -93
- package/studio/ferramentas/traco.md +0 -79
- package/studio/server.py +0 -2254
- package/studio/studio.log +0 -57
- package/studio/voz.py +0 -388
- package/studio/web/analise.html +0 -52
- package/studio/web/core.css +0 -1167
- package/studio/web/fontes/bebas.woff2 +0 -0
- package/studio/web/fontes/grotesk-700.woff2 +0 -0
- package/studio/web/fontes/inter-400.woff2 +0 -0
- package/studio/web/fontes/inter-700.woff2 +0 -0
- package/studio/web/fontes/jetbrains-400.woff2 +0 -0
- package/studio/web/fontes/playfair-700.woff2 +0 -0
- package/studio/web/fontes.css +0 -23
- package/studio/web/home.html +0 -217
- package/studio/web/js/analise.js +0 -510
- package/studio/web/js/audio.js +0 -607
- package/studio/web/js/editor.js +0 -1802
- package/studio/web/js/exportar.js +0 -222
- package/studio/web/js/ferramentas.js +0 -108
- package/studio/web/js/icones.js +0 -120
- package/studio/web/js/midia.js +0 -157
- package/studio/web/js/narracao.js +0 -325
- package/studio/web/js/player.js +0 -903
- package/studio/web/js/render-grade.js +0 -243
- package/studio/web/js/render-prosa.js +0 -104
- package/studio/web/js/render.js +0 -1852
- package/studio/web/js/sfx.js +0 -233
- package/studio/web/js/video.js +0 -464
- package/studio/web/js/voz-neural.js +0 -152
- package/studio/web/render.css +0 -1352
- package/studio/web/tf.html +0 -15
- package/studio/web/tool.html +0 -78
- package/studio/web/view.html +0 -27
package/lib/voz.js
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* voz.js — o lado Node do modo voz.
|
|
3
|
+
*
|
|
4
|
+
* O aplicativozinho da orb é Python (ver voz/primo_voz). O que mora aqui é a
|
|
5
|
+
* outra ponta: subir o processo, conversar com ele por JSON, e — a parte que
|
|
6
|
+
* importa — entregar cada pedido ao MESMO agente do terminal.
|
|
7
|
+
*
|
|
8
|
+
* ── POR QUE O CÉREBRO NÃO FOI PARA O PYTHON ──────────────────────────────
|
|
9
|
+
* O Jarvis mantinha uma sessão do Claude Code num processo filho e conversava
|
|
10
|
+
* por stream-json. Copiar aquele desenho aqui significaria uma segunda
|
|
11
|
+
* implementação do laço do agente, das quarenta ferramentas, do portão de
|
|
12
|
+
* permissão do computador e da corrente de conectores — em outra linguagem.
|
|
13
|
+
*
|
|
14
|
+
* Duas implementações do mesmo laço é a garantia de que uma delas está errada,
|
|
15
|
+
* e de que a correção de amanhã vai para só uma. Então o modo voz manda o
|
|
16
|
+
* texto para o `runAct` de sempre: as mesmas ferramentas, as mesmas skills, a
|
|
17
|
+
* mesma permissão, os mesmos conectores.
|
|
18
|
+
*
|
|
19
|
+
* ── O PEDIDO SAI DIFERENTE, E SÓ ISSO ────────────────────────────────────
|
|
20
|
+
* Uma resposta boa de ler é ruim de ouvir: lista com marcador, caminho de
|
|
21
|
+
* arquivo, bloco de código e trecho longo só funcionam para o olho. Então o
|
|
22
|
+
* pedido vai com uma instrução curta de FORMA — não de conteúdo. O agente
|
|
23
|
+
* continua fazendo o mesmo trabalho; ele só conta de outro jeito.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
'use strict';
|
|
27
|
+
|
|
28
|
+
const fs = require('fs');
|
|
29
|
+
const os = require('os');
|
|
30
|
+
const path = require('path');
|
|
31
|
+
const { spawn, execFileSync } = require('child_process');
|
|
32
|
+
|
|
33
|
+
const PASTA = path.join(__dirname, '..', 'voz');
|
|
34
|
+
|
|
35
|
+
/* A instrução de FORMA. Ela não muda o que o agente faz — muda como ele
|
|
36
|
+
conta. O que está proibido aqui é o que não existe em voz: marcador,
|
|
37
|
+
caminho, código, e parágrafo que ninguém segura de ouvido. */
|
|
38
|
+
const COMO_FALAR = `[MODO VOZ] A sua resposta vai ser LIDA EM VOZ ALTA para a pessoa, e ela não vê tela nenhuma.
|
|
39
|
+
|
|
40
|
+
Responda em no máximo 3 frases curtas, em português falado. Nada de lista com
|
|
41
|
+
marcador, nada de caminho de arquivo, nada de bloco de código, nada de
|
|
42
|
+
markdown — nada disso existe no ouvido de alguém.
|
|
43
|
+
|
|
44
|
+
Diga o que você FEZ e o que mudou, não como. Se algo deu errado, diga em uma
|
|
45
|
+
frase o que foi e o que você precisa.
|
|
46
|
+
|
|
47
|
+
Faça o trabalho inteiro normalmente, com as ferramentas de sempre. O que muda
|
|
48
|
+
é só o jeito de contar no fim.`;
|
|
49
|
+
|
|
50
|
+
/** Onde está o Python 3. Mesmo problema do Estúdio, mesma cura. */
|
|
51
|
+
function python() {
|
|
52
|
+
const nomes = process.platform === 'win32'
|
|
53
|
+
? ['python', 'py', 'python3']
|
|
54
|
+
: ['python3', 'python', '/opt/homebrew/bin/python3', '/usr/local/bin/python3', '/usr/bin/python3'];
|
|
55
|
+
for (const n of nomes) {
|
|
56
|
+
try {
|
|
57
|
+
const v = execFileSync(n, ['--version'], { stdio: ['ignore', 'pipe', 'pipe'], timeout: 5000 }).toString();
|
|
58
|
+
if (/Python 3/.test(v)) return n;
|
|
59
|
+
} catch { /* próximo */ }
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* O que falta para o modo voz abrir — e QUAL é a falta.
|
|
66
|
+
*
|
|
67
|
+
* A distinção é a diferença entre um recado que resolve e um que faz a pessoa
|
|
68
|
+
* dar voltas. Dois casos não se resolvem com pip:
|
|
69
|
+
*
|
|
70
|
+
* · `sounddevice` instalado, mas sem o PortAudio do sistema. O import
|
|
71
|
+
* explode com "PortAudio library not found", e mandar `pip install
|
|
72
|
+
* sounddevice` ali é mandar instalar o que já está instalado.
|
|
73
|
+
* · `tkinter` vem com o Python, mas algumas distribuições Linux o separam
|
|
74
|
+
* num pacote do sistema — e `pip install tkinter` não existe.
|
|
75
|
+
*
|
|
76
|
+
* Por isso a checagem lê a MENSAGEM do erro, e não só o fato de ter falhado.
|
|
77
|
+
*/
|
|
78
|
+
function faltando(py) {
|
|
79
|
+
const falta = [];
|
|
80
|
+
for (const [modulo, pacote] of [['numpy', 'numpy'], ['sounddevice', 'sounddevice'], ['tkinter', null]]) {
|
|
81
|
+
try {
|
|
82
|
+
execFileSync(py, ['-c', `import ${modulo}`], { stdio: ['ignore', 'pipe', 'pipe'], timeout: 20000 });
|
|
83
|
+
} catch (e) {
|
|
84
|
+
const saida = String((e.stderr || '') + (e.stdout || ''));
|
|
85
|
+
if (/portaudio/i.test(saida)) {
|
|
86
|
+
falta.push({ modulo, pacote: null, sistema: true, porque: 'o PortAudio, que é biblioteca do sistema' });
|
|
87
|
+
} else {
|
|
88
|
+
falta.push({ modulo, pacote });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return falta;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Como instalar uma biblioteca de sistema, neste sistema. */
|
|
96
|
+
const COMO_SISTEMA = {
|
|
97
|
+
portaudio: {
|
|
98
|
+
darwin: 'brew install portaudio',
|
|
99
|
+
linux: 'sudo apt install libportaudio2 (ou o equivalente da sua distribuição)',
|
|
100
|
+
win32: 'no Windows ele vem junto com o sounddevice — reinstale com pip',
|
|
101
|
+
},
|
|
102
|
+
tkinter: {
|
|
103
|
+
darwin: 'brew install python-tk',
|
|
104
|
+
linux: 'sudo apt install python3-tk',
|
|
105
|
+
win32: 'reinstale o Python pelo python.org, marcando "tcl/tk"',
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Confere o que é preciso, sem instalar nada.
|
|
111
|
+
*
|
|
112
|
+
* O tkinter é o caso especial: ele vem com o Python, mas em algumas
|
|
113
|
+
* distribuições Linux ele foi separado num pacote do SISTEMA — e `pip install
|
|
114
|
+
* tkinter` não existe. Dizer "instale com pip" ali seria mandar a pessoa a um
|
|
115
|
+
* lugar onde não há nada.
|
|
116
|
+
*/
|
|
117
|
+
function conferir() {
|
|
118
|
+
const py = python();
|
|
119
|
+
if (!py) {
|
|
120
|
+
return { ok: false, error: 'o modo voz precisa do Python 3, e não achei nenhum nesta máquina.',
|
|
121
|
+
comoResolver: 'instale em python.org e abra o terminal de novo' };
|
|
122
|
+
}
|
|
123
|
+
const falta = faltando(py);
|
|
124
|
+
if (!falta.length) return { ok: true, python: py };
|
|
125
|
+
|
|
126
|
+
const pip = falta.filter((f) => f.pacote).map((f) => f.pacote);
|
|
127
|
+
const linhas = [];
|
|
128
|
+
if (pip.length) linhas.push(`${py} -m pip install ${pip.join(' ')}`);
|
|
129
|
+
if (falta.some((f) => f.modulo === 'sounddevice' && f.sistema)) {
|
|
130
|
+
linhas.push(COMO_SISTEMA.portaudio[process.platform] || COMO_SISTEMA.portaudio.linux);
|
|
131
|
+
}
|
|
132
|
+
if (falta.some((f) => f.modulo === 'tkinter')) {
|
|
133
|
+
linhas.push(COMO_SISTEMA.tkinter[process.platform] || COMO_SISTEMA.tkinter.linux);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
ok: false,
|
|
138
|
+
python: py,
|
|
139
|
+
falta: falta.map((f) => f.modulo),
|
|
140
|
+
error: `falta o que o modo voz precisa: ${falta.map((f) => f.porque || f.modulo).join(', ')}`,
|
|
141
|
+
comoResolver: linhas.join('\n '),
|
|
142
|
+
// Só o que o pip resolve entra no "instalar agora": oferecer instalar
|
|
143
|
+
// o que ele não instala é prometer o que não se cumpre.
|
|
144
|
+
instalavel: pip,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Instala o que dá para instalar com pip. O tkinter não passa por aqui. */
|
|
149
|
+
function instalar(py, pacotes, aoFalar = () => {}) {
|
|
150
|
+
return new Promise((resolve) => {
|
|
151
|
+
aoFalar(`instalando ${pacotes.join(', ')} (uma vez, alguns minutos)`);
|
|
152
|
+
const p = spawn(py, ['-m', 'pip', 'install', '--quiet', ...pacotes]);
|
|
153
|
+
let erro = '';
|
|
154
|
+
p.stderr.on('data', (d) => { erro += d.toString(); });
|
|
155
|
+
p.on('close', (code) => resolve(code === 0
|
|
156
|
+
? { ok: true }
|
|
157
|
+
: { ok: false, error: erro.slice(-400).trim() || `pip saiu com ${code}` }));
|
|
158
|
+
p.on('error', (e) => resolve({ ok: false, error: e.message }));
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Abre o modo voz e fica de pé até a janela fechar.
|
|
164
|
+
*
|
|
165
|
+
* @param {object} op
|
|
166
|
+
* @param {string} op.python
|
|
167
|
+
* @param {string} op.servidor
|
|
168
|
+
* @param {string} op.token
|
|
169
|
+
* @param {string} op.voz
|
|
170
|
+
* @param {(texto:string)=>Promise<string>} op.pensar o agente de verdade
|
|
171
|
+
* @param {(texto:string)=>void} op.mostrar o que aparece no terminal
|
|
172
|
+
*/
|
|
173
|
+
function abrir({ python: py, servidor, token, voz, pensar, mostrar = () => {} }) {
|
|
174
|
+
return new Promise((resolve) => {
|
|
175
|
+
const p = spawn(py, ['-m', 'primo_voz'], {
|
|
176
|
+
cwd: PASTA,
|
|
177
|
+
env: {
|
|
178
|
+
...process.env,
|
|
179
|
+
PYTHONPATH: PASTA,
|
|
180
|
+
PRIMOCODE_SERVER: servidor,
|
|
181
|
+
PRIMOCODE_TOKEN: token || '',
|
|
182
|
+
PRIMOCODE_VOZ: voz || 'antonio',
|
|
183
|
+
PYTHONUNBUFFERED: '1',
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const manda = (obj) => {
|
|
188
|
+
try { p.stdin.write(JSON.stringify(obj) + '\n'); } catch { /* já fechou */ }
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
let buffer = '';
|
|
192
|
+
let ocupado = false;
|
|
193
|
+
|
|
194
|
+
p.stdout.on('data', async (d) => {
|
|
195
|
+
buffer += d.toString();
|
|
196
|
+
const linhas = buffer.split('\n');
|
|
197
|
+
buffer = linhas.pop();
|
|
198
|
+
for (const linha of linhas) {
|
|
199
|
+
if (!linha.trim()) continue;
|
|
200
|
+
let msg;
|
|
201
|
+
try { msg = JSON.parse(linha); } catch { continue; }
|
|
202
|
+
|
|
203
|
+
if (msg.tipo === 'fim') { try { p.kill(); } catch {} return; }
|
|
204
|
+
if (msg.tipo === 'erro') { mostrar(String(msg.texto || '')); continue; }
|
|
205
|
+
if (msg.tipo !== 'pedido') continue;
|
|
206
|
+
|
|
207
|
+
/* Um pedido por vez. A pessoa pode falar de novo enquanto ele
|
|
208
|
+
trabalha — e dois agentes rodando ao mesmo tempo na mesma
|
|
209
|
+
pasta é a receita para um escrever por cima do outro. */
|
|
210
|
+
if (ocupado) { manda({ tipo: 'resposta', texto: 'Ainda estou terminando o anterior.' }); continue; }
|
|
211
|
+
ocupado = true;
|
|
212
|
+
|
|
213
|
+
mostrar(String(msg.texto || ''));
|
|
214
|
+
manda({ tipo: 'estado', estado: 'pensando' });
|
|
215
|
+
try {
|
|
216
|
+
const resposta = await pensar(String(msg.texto || ''));
|
|
217
|
+
manda({ tipo: 'resposta', texto: resposta || 'Feito.' });
|
|
218
|
+
} catch (e) {
|
|
219
|
+
manda({ tipo: 'erro', texto: `Não consegui: ${e.message}` });
|
|
220
|
+
} finally {
|
|
221
|
+
ocupado = false;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// O Python fala com o terminal pela saída de ERRO, de propósito: o
|
|
227
|
+
// stdout inteiro é do protocolo, e uma linha solta ali quebraria a
|
|
228
|
+
// conversa entre os dois processos.
|
|
229
|
+
p.stderr.on('data', (d) => {
|
|
230
|
+
const texto = d.toString().trim();
|
|
231
|
+
if (texto) mostrar(texto, true);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
p.on('close', () => resolve({ ok: true }));
|
|
235
|
+
p.on('error', (e) => resolve({ ok: false, error: e.message }));
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
module.exports = { conferir, instalar, abrir, python, COMO_FALAR, PASTA };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "primocode",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.0",
|
|
4
4
|
"description": "PrimoCode — agente de engenharia com IA e cursor próprio. Requer conta Conecta Primo AI (Premium ou Super). Cria arquivos, roda comandos, controla navegador e desktop: abre apps, clica em botões e ícones pelo nome, digita e usa atalhos.",
|
|
5
5
|
"main": "bin/primocode.js",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"start": "node bin/primocode.js",
|
|
11
|
-
"test": "node test/tools.test.js && node test/ui.test.js && node test/
|
|
11
|
+
"test": "node test/tools.test.js && node test/ui.test.js && node test/entrada.test.js && node test/transparencia.test.js && node test/permissao.test.js && node test/skills.test.js && node test/estudio.test.js && node test/voz.test.js && node test/modo.test.js && node test/pasta.test.js && node test/catalogo.test.js && node test/desktop.test.js && node test/effort.test.js && node test/regressao.test.js && node test/memoria-conversa.test.js && node test/repeticao.test.js && node test/referencia.test.js && node test/parar.test.js && node test/continuar.test.js && node test/pipeline.test.js && node test/app.test.js && node test/aplicativo.test.js && node test/conta.test.mjs && node test/nuvem.test.js && node test/prazo.test.js && node test/primeira-vez.test.js && node test/janela.test.js && node test/pareamento.test.js && node test/fala.test.js && node test/especialistas.test.js && node test/empurrao.test.js"
|
|
12
12
|
},
|
|
13
13
|
"engines": {
|
|
14
14
|
"node": ">=18.17.0"
|
|
@@ -29,6 +29,15 @@
|
|
|
29
29
|
"lib/",
|
|
30
30
|
"app/",
|
|
31
31
|
"studio/",
|
|
32
|
-
"
|
|
32
|
+
"skills/",
|
|
33
|
+
"voz/",
|
|
34
|
+
"README.md",
|
|
35
|
+
"!**/__pycache__",
|
|
36
|
+
"!**/*.pyc",
|
|
37
|
+
"!**/*.pyo",
|
|
38
|
+
"!**/*.log",
|
|
39
|
+
"!studio/arquivos",
|
|
40
|
+
"!studio/midia",
|
|
41
|
+
"!studio/saida"
|
|
33
42
|
]
|
|
34
43
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
nome: Acessibilidade
|
|
3
|
+
descricao: interface que funciona para quem não usa mouse nem enxerga a tela
|
|
4
|
+
quando: acessibilidade, acessível, acessivel, a11y, aria, teclado, leitor de tela, contraste, semântica, semantica, html
|
|
5
|
+
autor: PrimoCode
|
|
6
|
+
---
|
|
7
|
+
Acessibilidade não é uma camada que se adiciona no fim. É como o HTML é
|
|
8
|
+
escrito.
|
|
9
|
+
|
|
10
|
+
**HTML semântico primeiro**: `button` para ação, `a` para navegação, `header`,
|
|
11
|
+
`nav`, `main`, `section`, `label`. Uma `div` com `onclick` não recebe foco,
|
|
12
|
+
não responde ao Enter e não existe para um leitor de tela. ARIA só entra
|
|
13
|
+
quando o elemento certo não existe — `aria-label` num `button` de ícone, sim;
|
|
14
|
+
`role="button"` numa `div`, não.
|
|
15
|
+
|
|
16
|
+
**Teclado**: dá para percorrer a página inteira com Tab, na ordem visual, e o
|
|
17
|
+
foco é VISÍVEL (`:focus-visible` com contorno de verdade — nunca
|
|
18
|
+
`outline: none` sem substituto). Modal prende o foco dentro e volta ao botão
|
|
19
|
+
que o abriu no Esc.
|
|
20
|
+
|
|
21
|
+
**Contraste**: 4.5:1 em texto normal, 3:1 em texto grande e em borda de
|
|
22
|
+
controle. Cinza-claro sobre branco é a falha mais comum.
|
|
23
|
+
|
|
24
|
+
**Imagem** tem `alt` que descreve a função, não o arquivo. Decorativa leva
|
|
25
|
+
`alt=""`.
|
|
26
|
+
|
|
27
|
+
**Formulário**: todo campo com `label` ligado, erro em texto (não só em
|
|
28
|
+
vermelho) e ligado ao campo por `aria-describedby`.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
nome: API que não quebra
|
|
3
|
+
descricao: rotas, validação, erro e segurança em servidor
|
|
4
|
+
quando: api, rota, rotas, endpoint, servidor, backend, express, fastapi, flask, django, rest, webhook, autenticação, autenticacao, token, banco de dados
|
|
5
|
+
autor: PrimoCode
|
|
6
|
+
---
|
|
7
|
+
Leia o que já existe (rotas, modelos, como o projeto trata erro e
|
|
8
|
+
configuração) e siga o padrão dele. Um projeto com dois padrões é pior que um
|
|
9
|
+
projeto com um padrão ruim.
|
|
10
|
+
|
|
11
|
+
**Valide na borda.** Toda entrada: tipo, tamanho, faixa. O erro responde com o
|
|
12
|
+
código HTTP certo e uma mensagem que diz o que corrigir — "Bad Request" não
|
|
13
|
+
diz nada a ninguém.
|
|
14
|
+
|
|
15
|
+
**Nunca**: segredo no código (vai para variável de ambiente, com o
|
|
16
|
+
`.env.example` atualizado); entrada do usuário concatenada em SQL, comando de
|
|
17
|
+
shell ou caminho de arquivo; catch vazio; dado pessoal no log.
|
|
18
|
+
|
|
19
|
+
**Separe** rota, regra de negócio e acesso a dados. A rota lê e responde; ela
|
|
20
|
+
não sabe fazer conta.
|
|
21
|
+
|
|
22
|
+
**Pense no que falha**: rede fora, disco cheio, campo ausente, mesmo pedido
|
|
23
|
+
chegando duas vezes. Uma rota que só funciona com o caminho feliz não está
|
|
24
|
+
pronta.
|
|
25
|
+
|
|
26
|
+
Antes de terminar, suba o servidor e mostre uma requisição respondendo de
|
|
27
|
+
verdade — com o corpo da resposta, não só o status.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
nome: Depurar de verdade
|
|
3
|
+
descricao: achar a causa do defeito em vez de tentar consertos no escuro
|
|
4
|
+
quando: bug, erro, defeito, quebrado, não funciona, nao funciona, falha, corrigir, consertar, debug, depurar, travando
|
|
5
|
+
autor: PrimoCode
|
|
6
|
+
---
|
|
7
|
+
Não conserte antes de reproduzir. Conserto sem reprodução é chute, e chute que
|
|
8
|
+
"parece ter resolvido" esconde o defeito para ele voltar depois.
|
|
9
|
+
|
|
10
|
+
**A ordem**:
|
|
11
|
+
|
|
12
|
+
1. **Reproduza.** Qual entrada, qual passo, o que aconteceu, o que deveria ter
|
|
13
|
+
acontecido. Se não reproduz, o defeito não está onde você acha.
|
|
14
|
+
2. **Leia o erro inteiro.** A primeira linha diz o sintoma; a pilha diz o
|
|
15
|
+
lugar. A linha que importa costuma ser a primeira que é do PROJETO, não da
|
|
16
|
+
biblioteca.
|
|
17
|
+
3. **Isole.** Metade de cada vez: o dado está errado ao entrar ou ao sair?
|
|
18
|
+
Antes ou depois desta função? Cada medição corta o espaço de busca pela
|
|
19
|
+
metade.
|
|
20
|
+
4. **Entenda a causa.** "Adicionei um try/catch e parou de aparecer" não é
|
|
21
|
+
causa, é mordaça.
|
|
22
|
+
5. **Conserte** o menor pedaço possível, e **prove** rodando a reprodução do
|
|
23
|
+
passo 1.
|
|
24
|
+
|
|
25
|
+
Se o projeto tem teste, escreva PRIMEIRO o que falha, depois a correção,
|
|
26
|
+
depois veja-o passar. Assim o defeito não volta sem ninguém ver.
|
|
27
|
+
|
|
28
|
+
Quando a suspeita for de ambiente (versão, variável, caminho), confira em vez
|
|
29
|
+
de supor: rode `--version`, imprima a variável, liste a pasta.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
nome: Editar o vídeo gravado
|
|
3
|
+
descricao: como tratar uma gravação do usuário sem estragar o ritmo dela
|
|
4
|
+
quando: gravei, gravação, gravacao, meu vídeo, meu video, editar, edição, edicao, corte, legenda, legendas, b-roll, broll
|
|
5
|
+
autor: PrimoCode
|
|
6
|
+
---
|
|
7
|
+
O vídeo é da pessoa. Ela apareceu, falou e errou — o seu trabalho é tirar o
|
|
8
|
+
que atrapalha, não refazer o que ela fez.
|
|
9
|
+
|
|
10
|
+
## A ordem que funciona
|
|
11
|
+
|
|
12
|
+
1. `estudio_video acao:"importar"` — o original entra na pasta do projeto, e
|
|
13
|
+
fica intocado. Nunca escreva por cima do arquivo dela.
|
|
14
|
+
2. `acao:"medir"` — duração, tamanho, fps. Enquadramento vertical e
|
|
15
|
+
horizontal mudam tudo o que vem depois.
|
|
16
|
+
3. `acao:"legendas"` — a transcrição com tempo. Ela serve para duas coisas: a
|
|
17
|
+
legenda em si e saber DO QUE ela está falando em cada instante, que é o
|
|
18
|
+
que decide onde entra apoio.
|
|
19
|
+
4. `acao:"cortar-silencio"` — depois de ler, não antes.
|
|
20
|
+
5. O plano, com a gravação como elemento de vídeo.
|
|
21
|
+
|
|
22
|
+
## Corte de silêncio
|
|
23
|
+
|
|
24
|
+
Pausa curta é fala, não erro. Corte só o que passa de ~0,6s, e deixe respiro
|
|
25
|
+
nas pontas (~0,18s). O padrão já faz isso; mexer nele é decisão, não ajuste.
|
|
26
|
+
|
|
27
|
+
Depois do corte, ASSISTA: peça quadros (`acao:"quadro"`) em alguns pontos de
|
|
28
|
+
emenda. Corte que fica bom no papel e ruim no ouvido é o normal, não a
|
|
29
|
+
exceção.
|
|
30
|
+
|
|
31
|
+
## Legenda
|
|
32
|
+
|
|
33
|
+
A legenda tem estilo — fonte, peso, cor, contorno, posição, animação. Ela não
|
|
34
|
+
é uma linha branca no rodapé por obrigação.
|
|
35
|
+
|
|
36
|
+
Regras que valem: no máximo 5 ou 6 palavras por vez; posição alta o bastante
|
|
37
|
+
para não ser coberta pela interface do aplicativo onde o vídeo vai; contorno
|
|
38
|
+
ou sombra, porque o fundo muda; e nunca cobrindo o rosto de quem fala.
|
|
39
|
+
|
|
40
|
+
## B-roll
|
|
41
|
+
|
|
42
|
+
Quando ela cita uma coisa concreta, essa coisa aparece — e ela some da tela
|
|
43
|
+
por 1 a 3 segundos. Depois volta. É isso que dá ritmo a vídeo falado.
|
|
44
|
+
|
|
45
|
+
Busque a imagem pelo que ela DISSE naquele instante (você tem os tempos da
|
|
46
|
+
transcrição). Volte sempre antes de a frase acabar.
|
|
47
|
+
|
|
48
|
+
## Troca de fundo
|
|
49
|
+
|
|
50
|
+
`acao:"recortar-pessoa"` devolve a pessoa com fundo transparente. Ponha uma
|
|
51
|
+
imagem relacionada ao assunto atrás — não uma textura decorativa.
|
|
52
|
+
|
|
53
|
+
O recorte erra na borda do cabelo. Se ficar com cara de adesivo, aumente o
|
|
54
|
+
`suavizar` e o `encolher` antes de desistir.
|
|
55
|
+
|
|
56
|
+
## O que contar para ela
|
|
57
|
+
|
|
58
|
+
Diga quantos segundos saíram e quantos cortes foram feitos. É fala dela que
|
|
59
|
+
sumiu do vídeo — ela tem o direito de saber, e de discordar.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
nome: Escrever em português
|
|
3
|
+
descricao: texto de produto que soa como gente, não como manual traduzido
|
|
4
|
+
quando: texto, copy, escrever, redação, redacao, mensagem, microcopy, erro, aviso, botão, botao, e-mail, email, post, legenda
|
|
5
|
+
autor: PrimoCode
|
|
6
|
+
---
|
|
7
|
+
Escreva como alguém que conhece o assunto falaria com um colega — em português
|
|
8
|
+
do Brasil, não em inglês traduzido.
|
|
9
|
+
|
|
10
|
+
**O que denuncia tradução**: "Nós fornecemos soluções", "Clique aqui para",
|
|
11
|
+
"Oops! Algo deu errado", voz passiva em tudo, "seu/sua" em toda frase,
|
|
12
|
+
gerúndio de call center ("vou estar enviando").
|
|
13
|
+
|
|
14
|
+
**Mensagem de erro** diz três coisas, nesta ordem: o que aconteceu, por que, e
|
|
15
|
+
o que fazer agora. "Erro 500" não é nenhuma das três. Sem culpar a pessoa: "o
|
|
16
|
+
e-mail precisa de @" e não "você digitou errado".
|
|
17
|
+
|
|
18
|
+
**Botão** é um verbo que descreve o resultado: "Salvar alterações", "Enviar
|
|
19
|
+
pedido" — nunca "OK", "Enviar" solto ou "Clique aqui".
|
|
20
|
+
|
|
21
|
+
**Frase curta.** Se precisou de vírgula para respirar duas vezes, são duas
|
|
22
|
+
frases. Corte advérbio ("simplesmente", "basicamente", "rapidamente") e
|
|
23
|
+
superlativo sem número.
|
|
24
|
+
|
|
25
|
+
Número concreto vence adjetivo: "responde em 2 segundos" vale mais que
|
|
26
|
+
"ultrarrápido".
|
|
27
|
+
|
|
28
|
+
Não use emoji para dar emoção a um texto que não tem nenhuma.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
nome: Git limpo
|
|
3
|
+
descricao: commit, branch e histórico que alguém consegue ler depois
|
|
4
|
+
quando: git, commit, commitar, branch, pull request, pr, merge, histórico, historico, versionar
|
|
5
|
+
autor: PrimoCode
|
|
6
|
+
---
|
|
7
|
+
O histórico é documentação. Quem vai lê-lo é você daqui a seis meses,
|
|
8
|
+
procurando por que uma linha existe.
|
|
9
|
+
|
|
10
|
+
**Commit**: um assunto por commit. A primeira linha diz o que MUDA no
|
|
11
|
+
comportamento, no imperativo e sem ponto final ("corrige o cálculo do frete
|
|
12
|
+
para pedido sem CEP"). O corpo diz POR QUE — o que estava errado e o que se
|
|
13
|
+
tentou antes. O código já mostra o que foi feito; o que ele não mostra é o
|
|
14
|
+
motivo.
|
|
15
|
+
|
|
16
|
+
**Nunca** commite: segredo, chave, `.env`, `node_modules`, pasta de build,
|
|
17
|
+
arquivo de editor. Confira com `git status` antes, e com `git diff --staged`
|
|
18
|
+
antes de fechar.
|
|
19
|
+
|
|
20
|
+
**Antes de commitar**, rode o que o projeto roda (lint, teste). Commit que
|
|
21
|
+
quebra a build custa o tempo de todo mundo que der pull.
|
|
22
|
+
|
|
23
|
+
**Branch** com nome que diz o assunto, não o seu nome.
|
|
24
|
+
|
|
25
|
+
**Pull request**: título que é a frase do commit; corpo com o que muda, por
|
|
26
|
+
que, e como conferir. Se o projeto tem template de PR, siga o template.
|
|
27
|
+
|
|
28
|
+
Nunca reescreva histórico que já foi empurrado e que outra pessoa pode ter.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
nome: Motion de primeira
|
|
3
|
+
descricao: como um vídeo criado do zero deixa de parecer feito por máquina
|
|
4
|
+
quando: vídeo, video, motion, animação, animacao, anúncio, anuncio, reels, teaser, abertura, comercial, propaganda, estúdio, estudio
|
|
5
|
+
autor: PrimoCode
|
|
6
|
+
---
|
|
7
|
+
Não existe template. Cada propriedade deste vídeo é uma decisão sua, e a
|
|
8
|
+
primeira decisão é **não repetir o vídeo anterior**.
|
|
9
|
+
|
|
10
|
+
## O que denuncia vídeo feito por IA
|
|
11
|
+
|
|
12
|
+
Não faça nada disto, em nenhum vídeo:
|
|
13
|
+
|
|
14
|
+
- gradiente roxo-para-azul (o mais reconhecível de todos), e gradiente de duas
|
|
15
|
+
cores que não têm relação com o assunto;
|
|
16
|
+
- tudo centralizado, do primeiro ao último quadro;
|
|
17
|
+
- uma fonte só, em todos os tamanhos;
|
|
18
|
+
- texto que aparece com `opacidade 0→1` e mais nada, cena após cena;
|
|
19
|
+
- ícone genérico flutuando ao lado de cada frase;
|
|
20
|
+
- tempo igual em todas as cenas;
|
|
21
|
+
- transição igual entre todas.
|
|
22
|
+
|
|
23
|
+
## O que separa motion bom de slide animado
|
|
24
|
+
|
|
25
|
+
**A câmera existe.** Zoom, pan e dolly são da CENA, não do elemento. Um zoom
|
|
26
|
+
lento de 1.0 para 1.08 ao longo de uma cena dá vida a um quadro parado — e
|
|
27
|
+
quase nenhum vídeo automático faz isso.
|
|
28
|
+
|
|
29
|
+
**Nada entra do nada.** Um elemento entra vindo de algum lugar (de baixo, de
|
|
30
|
+
trás, de fora do quadro), com `saida` ou `elastico` na suavização. Movimento
|
|
31
|
+
linear é a assinatura da máquina: no mundo físico nada começa e para na mesma
|
|
32
|
+
velocidade.
|
|
33
|
+
|
|
34
|
+
**Profundidade.** Camadas que se movem em velocidades diferentes (parallax)
|
|
35
|
+
custam duas linhas e mudam a cena inteira: fundo devagar, meio médio, frente
|
|
36
|
+
rápido. Com `perspectiva` na cena, `rotacaoX`/`rotacaoY`/`z` viram 3D de
|
|
37
|
+
verdade.
|
|
38
|
+
|
|
39
|
+
**Ritmo.** Cena de informação simples: 1,5 a 2,5s. Cena com frase para ler: 3
|
|
40
|
+
a 4s. Fecho: 2s. Variar a duração é o que cria ritmo; repetir cria sono.
|
|
41
|
+
|
|
42
|
+
**Silêncio visual.** Um quadro com uma frase e mais nada vale mais que um com
|
|
43
|
+
seis elementos. Espaço vazio é composição, não desperdício.
|
|
44
|
+
|
|
45
|
+
## Cor e tipo
|
|
46
|
+
|
|
47
|
+
Escolha a paleta a partir do ASSUNTO, e escreva os valores. Três a cinco
|
|
48
|
+
cores: uma dominante, uma de destaque, neutros com viés da dominante. Se a
|
|
49
|
+
marca existe, leia o site dela com `estudio_site` e use as cores medidas —
|
|
50
|
+
não as que você imagina que ela usa.
|
|
51
|
+
|
|
52
|
+
Duas fontes, no máximo: uma de display para o que grita, uma neutra para o
|
|
53
|
+
que se lê. `estudio_midia acao:"fontes"` mostra um leque grande — sair do
|
|
54
|
+
Inter/Montserrat é metade do trabalho de não parecer genérico.
|
|
55
|
+
|
|
56
|
+
## Antes de renderizar
|
|
57
|
+
|
|
58
|
+
- Todo `src` aponta para arquivo que existe na pasta (baixe antes).
|
|
59
|
+
- Os tempos das cenas batem com os tempos MEDIDOS da narração.
|
|
60
|
+
- Nenhuma cena tem a mesma composição da anterior.
|
|
61
|
+
- Leia o seu próprio plano e pergunte: em que este vídeo é diferente do
|
|
62
|
+
último que eu fiz? Se não houver resposta, refaça antes de renderizar.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
nome: Página que converte
|
|
3
|
+
descricao: estrutura e acabamento de landing page, site e página de venda
|
|
4
|
+
quando: landing, landing page, site, página, pagina, home, hero, seção, secao, cta, conversão, conversao, vendas, institucional
|
|
5
|
+
autor: PrimoCode
|
|
6
|
+
---
|
|
7
|
+
Uma página que converte tem ordem, não mais elementos.
|
|
8
|
+
|
|
9
|
+
**A ordem que funciona**: promessa clara em até 8 palavras → uma linha que
|
|
10
|
+
explica para quem é → prova (número real, print, nome de cliente) → o que a
|
|
11
|
+
pessoa ganha, em 3 blocos → objeção respondida → um único pedido de ação,
|
|
12
|
+
repetido no fim.
|
|
13
|
+
|
|
14
|
+
**Um CTA por página.** Dois pedidos de ação competem entre si e a pessoa não
|
|
15
|
+
faz nenhum.
|
|
16
|
+
|
|
17
|
+
**O que denuncia página genérica** — não faça nada disto:
|
|
18
|
+
gradiente roxo-para-azul no fundo, tudo centralizado do topo ao rodapé,
|
|
19
|
+
sombra em todo cartão, emoji no lugar de ícone, "Bem-vindo ao nosso site",
|
|
20
|
+
"Soluções inovadoras", texto de exemplo em qualquer lugar.
|
|
21
|
+
|
|
22
|
+
**Acabamento**: escala de espaço consistente (4/8/12/16/24/32/48), no máximo
|
|
23
|
+
dois pesos de fonte, contraste de 4.5:1 no texto, botão com hover e
|
|
24
|
+
focus-visible, largura de leitura entre 60 e 75 caracteres. Funciona de 360px
|
|
25
|
+
a 1440px sem rolagem horizontal.
|
|
26
|
+
|
|
27
|
+
Escreva o texto de verdade, sobre o assunto de verdade. Uma página bonita com
|
|
28
|
+
texto vazio não convence ninguém.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
nome: Performance web
|
|
3
|
+
descricao: página que carrega rápido de verdade, não no papel
|
|
4
|
+
quando: performance, lento, lenta, rápido, rapido, otimizar, otimização, otimizacao, carregamento, lighthouse, bundle, imagem, imagens
|
|
5
|
+
autor: PrimoCode
|
|
6
|
+
---
|
|
7
|
+
Meça antes de otimizar. Otimizar por palpite muda código sem mudar o tempo.
|
|
8
|
+
|
|
9
|
+
**O que quase sempre é o culpado, nesta ordem**: imagem gigante servida em
|
|
10
|
+
tamanho de tela cheia; fonte externa bloqueando a renderização; JavaScript que
|
|
11
|
+
roda antes de a página aparecer; biblioteca inteira importada para usar uma
|
|
12
|
+
função.
|
|
13
|
+
|
|
14
|
+
**Imagem**: dimensione para o tamanho em que aparece, use formato moderno
|
|
15
|
+
(WebP/AVIF), declare `width` e `height` no HTML (sem isso a página pula
|
|
16
|
+
enquanto carrega) e `loading="lazy"` no que está abaixo da dobra.
|
|
17
|
+
|
|
18
|
+
**Fonte**: `font-display: swap`, e prefira a fonte do sistema quando a marca
|
|
19
|
+
não exige outra. Uma fonte externa custa uma conexão e um bloqueio.
|
|
20
|
+
|
|
21
|
+
**JavaScript**: nada que não seja necessário para a primeira tela. `defer` no
|
|
22
|
+
que puder esperar. Antes de adicionar uma biblioteca, escreva a função — três
|
|
23
|
+
linhas suas custam menos que 40 KB de dependência.
|
|
24
|
+
|
|
25
|
+
**CSS**: evite seletor que força recálculo em rolagem; anime só `transform` e
|
|
26
|
+
`opacity`.
|
|
27
|
+
|
|
28
|
+
Prove com número: o tamanho do que é baixado antes e depois.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
nome: Revisão antes de entregar
|
|
3
|
+
descricao: confere o próprio trabalho antes de dizer que acabou
|
|
4
|
+
quando: pronto, terminar, entregar, finalizar, revisar, conferir, testar, verificar
|
|
5
|
+
autor: PrimoCode
|
|
6
|
+
---
|
|
7
|
+
Antes de dizer que terminou, PROVE. A mentira mais comum de um agente é
|
|
8
|
+
"pronto" sem prova, e ela custa a confiança inteira.
|
|
9
|
+
|
|
10
|
+
O que conta como prova, por tipo de entrega:
|
|
11
|
+
|
|
12
|
+
- **Página HTML**: abra com `browser_open` e leia o console. Erro no console é
|
|
13
|
+
tarefa inacabada, mesmo que a página pareça certa. Confira que o texto
|
|
14
|
+
aparece de verdade — página em branco por TypeError na primeira linha
|
|
15
|
+
responde 200 e tem título.
|
|
16
|
+
- **Código com teste**: rode o comando de teste do projeto e mostre a saída
|
|
17
|
+
real. Nunca escreva "os testes passam" sem a saída na mão.
|
|
18
|
+
- **Código sem teste**: execute o caminho principal uma vez. Se não dá para
|
|
19
|
+
executar, diga isso em vez de afirmar que funciona.
|
|
20
|
+
- **Arquivo de configuração**: leia de volta o que escreveu.
|
|
21
|
+
|
|
22
|
+
Releia o seu próprio diff antes de terminar, procurando o que você mesmo
|
|
23
|
+
quebraria: caminho que não existe, promessa sem await, variável que só existe
|
|
24
|
+
num dos ramos, texto de exemplo esquecido.
|
|
25
|
+
|
|
26
|
+
Se algo ficou por fazer, diga em UMA linha o que foi e por quê. Entregar 90%
|
|
27
|
+
dizendo a verdade vale mais que entregar 90% dizendo 100%.
|