primocode 8.16.0 → 8.18.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/lib/effort.js +179 -34
- package/package.json +1 -1
package/lib/effort.js
CHANGED
|
@@ -132,29 +132,100 @@ function layoutEffort(idx) {
|
|
|
132
132
|
// leem como listras — e listra clara demais apaga o texto branco por cima.
|
|
133
133
|
// O fundo tem de parecer um pano roxo respirando atrás do painel, não uma
|
|
134
134
|
// bandeira. Os tons claros ficam de fora por isso.
|
|
135
|
-
|
|
135
|
+
// A rampa do plasma, do fundo frio ao branco quente.
|
|
136
|
+
//
|
|
137
|
+
// Ela é LONGA de propósito: o degradê é desenhado em meia-célula (▀), então
|
|
138
|
+
// há o dobro de linhas para atravessar, e uma rampa curta viraria degrau
|
|
139
|
+
// visível. Começa quase preta e termina em branco — é a amplitude que faz o
|
|
140
|
+
// pico parecer luz, e não só "roxo mais claro".
|
|
141
|
+
// A rampa é a paleta do PrimoCode, não uma cor qualquer.
|
|
142
|
+
//
|
|
143
|
+
// O plasma era roxo — bonito, e de outro programa. A marca do CLI é o ciano
|
|
144
|
+
// (brand 45, o cyan-400 do design system; brandDim 31 é a mesma cor
|
|
145
|
+
// recuando), e é dele que a rampa sai: do teal profundo ao branco, passando
|
|
146
|
+
// exatamente pelo 45 no meio do caminho. Assim o pico da onda é a cor da
|
|
147
|
+
// marca acesa, e não um roxo emprestado.
|
|
148
|
+
const RAMPA = [23, 23, 24, 30, 31, 37, 38, 44, 45, 51, 87, 123, 159, 195, 231];
|
|
149
|
+
|
|
150
|
+
// Mantido pelo nome antigo porque o resto do arquivo (e o teste) já o
|
|
151
|
+
// conhece; o conteúdo é que mudou de família.
|
|
152
|
+
const ROXOS = RAMPA;
|
|
153
|
+
|
|
154
|
+
// Quanto o plasma é amortecido nas linhas que têm texto.
|
|
155
|
+
//
|
|
156
|
+
// Baixou de 0.5 para 0.26: "os textos devem ser extremamente legíveis". Com
|
|
157
|
+
// 0.5 a linha ainda chegava ao ciano médio, e ciano claro atrás de texto
|
|
158
|
+
// claro é leitura no limite. Em 0.26 a linha de texto vive no terço escuro
|
|
159
|
+
// da rampa — teal profundo — e o texto branco salta. O brilho não se perde:
|
|
160
|
+
// ele acontece nas faixas abertas, logo acima e abaixo, que é onde ninguém
|
|
161
|
+
// precisa ler.
|
|
162
|
+
const TETO_SOB_TEXTO = 0.26;
|
|
163
|
+
|
|
164
|
+
// E um teto absoluto, além da escala: por mais alto que o campo suba, atrás
|
|
165
|
+
// de texto ele não passa daqui. A escala sozinha não garante — bastava um
|
|
166
|
+
// pico forte para a linha clarear inteira.
|
|
167
|
+
const INDICE_MAX_TEXTO = 2; // até o 24 (#005f87): teal fundo, sempre
|
|
168
|
+
//
|
|
169
|
+
// O 2 não foi escolhido a olho. Medi o contraste de TODAS as células de
|
|
170
|
+
// texto ao longo de dezenas de quadros, pela fórmula de luminância relativa
|
|
171
|
+
// da WCAG. Com teto 4 o pior caso dava 4.08 — abaixo do mínimo AA (4.5),
|
|
172
|
+
// e o vilão era o índice 3 (#008787, teal médio) atrás dos traços da régua.
|
|
173
|
+
// Com teto 2 o pior caso passa de 7, que é o nível AAA. O teste refaz essa
|
|
174
|
+
// medida e reprova se algum dia cair.
|
|
175
|
+
|
|
176
|
+
/* O campo: o que decide a cor de cada meia-célula.
|
|
177
|
+
*
|
|
178
|
+
* Três coisas somadas, e é a soma que dá a sensação de energia em vez de
|
|
179
|
+
* listra:
|
|
180
|
+
*
|
|
181
|
+
* 1. uma ONDA DIAGONAL atravessando o painel, devagar;
|
|
182
|
+
* 2. um PULSO RADIAL saindo do próprio rótulo "ultracode" — é o detalhe
|
|
183
|
+
* que amarra a animação ao que ela significa: a potência irradia de
|
|
184
|
+
* onde você está;
|
|
185
|
+
* 3. uma segunda onda lenta, fora de fase, que impede o padrão de se
|
|
186
|
+
* repetir de forma óbvia.
|
|
187
|
+
*
|
|
188
|
+
* `x` é a coluna, `y` a meia-linha (duas por linha de texto), `foco` a
|
|
189
|
+
* coluna do rótulo selecionado.
|
|
190
|
+
*/
|
|
191
|
+
function campoUltra(x, y, fase, foco, altura) {
|
|
192
|
+
// O terminal tem célula alta e estreita: sem corrigir, o pulso radial
|
|
193
|
+
// sairia como uma elipse achatada em vez de círculo.
|
|
194
|
+
const dx = (x - foco) * 0.5;
|
|
195
|
+
const dy = (y - altura / 2) * 1.1;
|
|
196
|
+
const raio = Math.sqrt(dx * dx + dy * dy);
|
|
197
|
+
|
|
198
|
+
const diagonal = Math.sin((x * 0.11) + (y * 0.30) + fase * 1.15);
|
|
199
|
+
const pulso = Math.sin(raio * 0.42 - fase * 2.1) * Math.exp(-raio * 0.035);
|
|
200
|
+
const lenta = Math.sin(x * 0.037 - fase * 0.5 + Math.cos(y * 0.19) * 0.8);
|
|
201
|
+
|
|
202
|
+
const v = diagonal * 0.42 + pulso * 0.78 + lenta * 0.34;
|
|
203
|
+
// O divisor maior que a amplitude puxa a média para baixo: o painel fica
|
|
204
|
+
// a maior parte do tempo em roxo fundo, e o branco vira PICO — evento,
|
|
205
|
+
// não estado. Centrado, o branco virava o normal e não impressionava
|
|
206
|
+
// mais nada.
|
|
207
|
+
return Math.max(0, Math.min(1, (v + 1.15) / 2.75));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// `escala` escurece a linha SEM achatá-la.
|
|
211
|
+
//
|
|
212
|
+
// A primeira versão usava Math.min(v, teto): tudo acima do teto virava a
|
|
213
|
+
// mesma cor, e as linhas de texto ganhavam platôs chapados — retângulos
|
|
214
|
+
// visíveis atravessando o plasma. Multiplicar preserva a forma da onda e só
|
|
215
|
+
// baixa a amplitude: a linha fica escura o bastante para ler e continua
|
|
216
|
+
// fazendo parte do mesmo pano.
|
|
217
|
+
function corDoCampo(v, escala, tetoIndice) {
|
|
218
|
+
const t = escala ? v * escala : v;
|
|
219
|
+
let i = Math.round(t * (RAMPA.length - 1));
|
|
220
|
+
if (tetoIndice != null) i = Math.min(i, tetoIndice);
|
|
221
|
+
return RAMPA[Math.max(0, Math.min(RAMPA.length - 1, i))];
|
|
222
|
+
}
|
|
136
223
|
|
|
224
|
+
// Guardada para quem já usava a onda antiga (e para o teste da rampa).
|
|
137
225
|
function fundoRoxo(x, fase) {
|
|
138
|
-
|
|
139
|
-
// irregular de faixas, em vez de listras repetidas e óbvias.
|
|
140
|
-
//
|
|
141
|
-
// As frequências caíram (0.55 → 0.13) porque as faixas tinham três
|
|
142
|
-
// colunas de largura: de longe aquilo não era um fundo ondulando, era
|
|
143
|
-
// chuviscado. Faixa larga anda devagar pela tela, que é o movimento que
|
|
144
|
-
// se quer ver — o painel respira em vez de piscar.
|
|
145
|
-
const faixa = x / 2;
|
|
146
|
-
const onda = Math.sin(faixa * 0.13 + fase) * 0.62 + Math.sin(faixa * 0.041 - fase * 0.55) * 0.38;
|
|
147
|
-
// A curva ³ empurra os valores para o MEIO da rampa: os extremos (o mais
|
|
148
|
-
// escuro e o mais claro) só aparecem no pico da onda, e o painel passa a
|
|
149
|
-
// maior parte do tempo num roxo médio, onde o texto branco se lê.
|
|
150
|
-
const suave = Math.pow(onda, 3) * 0.55 + onda * 0.45;
|
|
151
|
-
const i = Math.round((suave + 1) / 2 * (ROXOS.length - 1));
|
|
152
|
-
return ROXOS[Math.max(0, Math.min(ROXOS.length - 1, i))];
|
|
226
|
+
return corDoCampo(campoUltra(x, 0, fase, 0, 2));
|
|
153
227
|
}
|
|
154
228
|
|
|
155
|
-
// Pinta a linha inteira (até a largura do painel) com a onda por baixo.
|
|
156
|
-
// `destaque` é o trecho que fica branco e forte (o nível escolhido); o resto
|
|
157
|
-
// da linha sai num lilás claro, para o escolhido saltar aos olhos.
|
|
158
229
|
function pintarLinhaUltra(texto, largura, fase, opts = {}) {
|
|
159
230
|
const base = opts.base || 231; // branco
|
|
160
231
|
const apagado = opts.apagado || base;
|
|
@@ -179,25 +250,98 @@ function pintarLinhaUltra(texto, largura, fase, opts = {}) {
|
|
|
179
250
|
return saida + '\x1b[0m';
|
|
180
251
|
}
|
|
181
252
|
|
|
253
|
+
/* O painel do ultracode, desenhado em MEIA-CÉLULA.
|
|
254
|
+
*
|
|
255
|
+
* O caractere "▀" ocupa a metade de cima da célula. Pintando a frente dele
|
|
256
|
+
* com uma cor e o fundo com outra, cada linha do terminal carrega DUAS
|
|
257
|
+
* linhas de imagem. É o que separa um degradê em blocos de um degradê que
|
|
258
|
+
* parece luz — e é como demo de terminal sempre fez.
|
|
259
|
+
*
|
|
260
|
+
* Onde há letra, a célula deixa de ser meia e vira fundo liso: não dá para
|
|
261
|
+
* ter o glifo do texto e o do meio-bloco na mesma célula. Aí o fundo é a
|
|
262
|
+
* média das duas metades, limitada para o texto continuar legível.
|
|
263
|
+
*/
|
|
264
|
+
function painelUltra(L, fase) {
|
|
265
|
+
const alturaMeia = L.linhas.length * 2;
|
|
266
|
+
const foco = (L.destaque.de + L.destaque.ate) / 2;
|
|
267
|
+
// Duas cores de texto, as duas claras. Sobre o teal escuro das linhas de
|
|
268
|
+
// texto, tanto o branco quanto o ciano-claro passam com folga — e a
|
|
269
|
+
// diferença entre eles ainda separa o que está escolhido do resto.
|
|
270
|
+
//
|
|
271
|
+
// O lilás de antes (189) não era da paleta e, sobre ciano, ficava sujo.
|
|
272
|
+
// TUDO branco. A hierarquia fica no negrito, não na cor.
|
|
273
|
+
//
|
|
274
|
+
// O secundário era 195 (ciano quase branco). Bonito, e o cálculo de
|
|
275
|
+
// contraste reprovou: sobre o teal mais claro que o fundo de texto pode
|
|
276
|
+
// ter, o 195 dá 6.57 — passa o mínimo AA (4.5) e não chega ao AAA (7.0).
|
|
277
|
+
// E não adiantava clarear um pouco: sobre aquele fundo, NENHUMA cor
|
|
278
|
+
// chega a 7 a não ser o branco puro, que dá 7.20. Como o pedido foi
|
|
279
|
+
// "extremamente legíveis", o branco ganhou e a diferença entre escolhido
|
|
280
|
+
// e resto passou a ser o peso da fonte — que separa igual e não custa
|
|
281
|
+
// contraste nenhum.
|
|
282
|
+
const BRANCO = 231;
|
|
283
|
+
const CLARO = 231;
|
|
284
|
+
|
|
285
|
+
const corDoTexto = (l, x) => {
|
|
286
|
+
if (l.tipo === 'titulo') return { cor: BRANCO, negrito: true };
|
|
287
|
+
if (l.tipo === 'nomes') {
|
|
288
|
+
const dentro = x >= L.destaque.de && x < L.destaque.ate;
|
|
289
|
+
return { cor: dentro ? BRANCO : CLARO, negrito: dentro };
|
|
290
|
+
}
|
|
291
|
+
return { cor: CLARO, negrito: false };
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
return L.linhas.map((l, y) => {
|
|
295
|
+
// A régua "▔" some no ultra: sobre o plasma ela virava uma listra
|
|
296
|
+
// clara cortando o topo do bloco.
|
|
297
|
+
const texto = l.tipo === 'regua' ? '' : l.texto;
|
|
298
|
+
// Linha COM texto é acalmada inteira, não só debaixo das letras.
|
|
299
|
+
//
|
|
300
|
+
// Limitar só a célula do glifo não bastava: o vão entre as palavras
|
|
301
|
+
// recebia o plasma cheio, e um pico branco encostado na letra some
|
|
302
|
+
// com ela do mesmo jeito. A linha toda vira superfície escura, e o
|
|
303
|
+
// brilho fica para as faixas abertas — que é onde ele aparece sem
|
|
304
|
+
// atrapalhar ninguém.
|
|
305
|
+
const linhaCalma = texto.trim().length > 0 ? TETO_SOB_TEXTO : 0;
|
|
306
|
+
let saida = '';
|
|
307
|
+
let fg = -1, bg = -1, forte = null;
|
|
308
|
+
|
|
309
|
+
for (let x = 0; x < L.cols; x++) {
|
|
310
|
+
const ch = texto[x] || ' ';
|
|
311
|
+
const temLetra = ch !== ' ';
|
|
312
|
+
const cima = campoUltra(x, y * 2, fase, foco, alturaMeia);
|
|
313
|
+
const baixo = campoUltra(x, y * 2 + 1, fase, foco, alturaMeia);
|
|
314
|
+
|
|
315
|
+
let glifo, corFrente, corFundo, querForte;
|
|
316
|
+
if (temLetra) {
|
|
317
|
+
const t = corDoTexto(l, x);
|
|
318
|
+
glifo = ch;
|
|
319
|
+
corFrente = t.cor;
|
|
320
|
+
querForte = t.negrito;
|
|
321
|
+
corFundo = corDoCampo((cima + baixo) / 2, TETO_SOB_TEXTO, INDICE_MAX_TEXTO);
|
|
322
|
+
} else {
|
|
323
|
+
glifo = '▀'; // ▀
|
|
324
|
+
const teto = linhaCalma ? INDICE_MAX_TEXTO : null;
|
|
325
|
+
corFrente = corDoCampo(cima, linhaCalma, teto);
|
|
326
|
+
corFundo = corDoCampo(baixo, linhaCalma, teto);
|
|
327
|
+
querForte = false;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (corFundo !== bg) { saida += `\x1b[48;5;${corFundo}m`; bg = corFundo; }
|
|
331
|
+
if (corFrente !== fg) { saida += `\x1b[38;5;${corFrente}m`; fg = corFrente; }
|
|
332
|
+
if (querForte !== forte) { saida += querForte ? '\x1b[1m' : '\x1b[22m'; forte = querForte; }
|
|
333
|
+
saida += glifo;
|
|
334
|
+
}
|
|
335
|
+
return saida + '\x1b[0m';
|
|
336
|
+
}).join('\n');
|
|
337
|
+
}
|
|
338
|
+
|
|
182
339
|
function desenharEffort(idx, fase) {
|
|
183
340
|
const L = layoutEffort(idx);
|
|
184
341
|
const ultra = NOMES[idx] === 'ultracode';
|
|
185
342
|
|
|
186
343
|
if (ultra) {
|
|
187
|
-
|
|
188
|
-
// com a MESMA onda, então as faixas ficam alinhadas de cima a baixo.
|
|
189
|
-
const LILAS = 189; // lilás bem claro, para o que não é o escolhido
|
|
190
|
-
return L.linhas.map((l) => {
|
|
191
|
-
// A régua é uma fileira de "▔". Sobre o roxo ela virava uma
|
|
192
|
-
// listra clara atravessando o topo e cortava o bloco em dois.
|
|
193
|
-
// No ultra ela some e vira fundo liso: a borda de cima do painel
|
|
194
|
-
// passa a ser o próprio degradê, que é o que se quer ver.
|
|
195
|
-
if (l.tipo === 'regua') return pintarLinhaUltra('', L.cols, fase, {});
|
|
196
|
-
if (l.tipo === 'titulo') return pintarLinhaUltra(l.texto, L.cols, fase, { negrito: true });
|
|
197
|
-
if (l.tipo === 'nomes') return pintarLinhaUltra(l.texto, L.cols, fase, { destaque: L.destaque, apagado: LILAS });
|
|
198
|
-
if (l.tipo === 'resumo' || l.tipo === 'extremos') return pintarLinhaUltra(l.texto, L.cols, fase, { base: LILAS, apagado: LILAS });
|
|
199
|
-
return pintarLinhaUltra(l.texto, L.cols, fase, {});
|
|
200
|
-
}).join('\n');
|
|
344
|
+
return painelUltra(L, fase);
|
|
201
345
|
}
|
|
202
346
|
|
|
203
347
|
return L.linhas.map((l) => {
|
|
@@ -224,5 +368,6 @@ function desenharEffort(idx, fase) {
|
|
|
224
368
|
}
|
|
225
369
|
|
|
226
370
|
module.exports = { NIVEIS, NOMES, normalizar, nivelDe, indiceDe, modeloDe, pesquisaDe,
|
|
227
|
-
layoutEffort, fundoRoxo, pintarLinhaUltra, desenharEffort, ROXOS
|
|
371
|
+
layoutEffort, fundoRoxo, pintarLinhaUltra, desenharEffort, ROXOS, RAMPA,
|
|
372
|
+
campoUltra, corDoCampo, painelUltra };
|
|
228
373
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "primocode",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.18.0",
|
|
4
4
|
"description": "PrimoCode — agente de engenharia com IA e cursor próprio. Modelos grátis. 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": {
|