Manual de Depuração Frontend Pryne
Sintoma → triagem para as demos vanilla-JS do Pryne: páginas HTML de arquivo único impulsionadas por uma espinha dorsal de módulo window.Roll (design-demos/js/roll-*.js), um shader WebGL com fallback 2D, um loop de renderização rAF, Lenis de rolagem suave vendido e GSAP carregado assíncrono do CDN como um aprimoramento progressivo.
ANTECEDENTES OBRIGATÓRIOS: superpowers:systematic-debugging detém a disciplina genérica de causa raiz (sem correções sem investigação). Siga-a; este skill fornece apenas a tabela de sintomas e armadilhas específicas do projeto.
Ferramentas: para saber como dirigir o navegador, capturar consoles, emular movimento reduzido e fazer rastreamentos, use pryne-browser-lab. Este skill pressupõe que você já pode executar esses comandos.
Leia o comentário do cabeçalho primeiro
Cada demonstração v4 (v4-a até v4-d em design-demos/) carrega seu histórico de auditoria como um comentário HTML bem no topo do arquivo — o que foi encontrado quebrado, o que foi corrigido e por quê. Verificado em todos os quatro arquivos em 22/07/2026. Antes de rediagnosticar qualquer coisa, faça head -30 na demonstração que você está depurando. Vários "bugs" que você encontrará estão documentados como regressões já corrigidas; se um reaparecer, você está procurando o que o reverteu, não uma nova causa.
Conheça também o layout da compilação (a partir de 22/07/2026): apenas v4-d-hybrid.html usa os módulos roll-*.js compartilhados. v4-a/b/c são compilações de comparação com escopo reduzido com seu próprio JS inline — as verificações específicas do Roll desta tabela não se aplicam a eles, mas as mesmas classes de falha se aplicam.
Zero erros de console é o estado de repouso
O padrão é zero erros de console (a rubrica CRITIQUE em design-demos/DECISIONS.md exige isso). v3 foi verificado com zero de acordo com o registro de status do projeto; as variantes v4 não estão certificadas, pendentes da campanha de direção (pryne-design-direction-decision). Qualquer erro de console é um defeito a ser triado, nunca ruído ambiente a ser ignorado.
Tabela de sintoma → triagem
| Sintoma | Causa provável | Verificação discriminadora |
|---|---|---|
| Animação/placa de desenvolvimento executa (ou termina) antes de sua seção ser rolada para a vista | Regressão de bloqueio de visibilidade. O comentário do cabeçalho v4-d registra isso como a correção de auditoria de maior prioridade: as placas de recurso "tickavam incondicionalmente desde o carregamento da página e terminavam de resolver antes que alguém rolasse para elas." O desenvolvimento deve ser bloqueado na classe .in do painel. | Experimento 1 abaixo |
| Animação de revelação recorta errado, pula ou nunca dispara | clip-path aplicado ao elemento que o IntersectionObserver observa, em vez de um wrapper interno. A correção do conceito-C (carregada para v4-d, conforme seu comentário do cabeçalho): a revelação do clip-path vive em um wrapper interno, nunca no elemento observado. | Inspecione o elemento: o nó observado e o nó com clip são o mesmo nó? |
| Cursor do SO desaparece, nenhum cursor personalizado o substitui | Não deve recorrer — corrigido em 22/07/2026 (encontrado por uma auditoria de teste frio, corrigido no mesmo dia): o manipulador por evento (roll-cursor.js:17-20) e seu local de chamada pointermove (roll-core.js:26-29) agora ambos capturam e restauram (null Roll.cursorUpdate, removem .custom-cursor), além da captura original no momento da configuração; z-index de #cur/#ring aumentado de 50 para 70 acima de #flash (60) para que o pulso do clímax não possa pintar sobre o cursor. Se o sintoma reaparecer, um desses guardiões regrediu ou um novo código esconde o cursor fora deste contrato. | document.body.classList.contains('custom-cursor') vs Roll.cursorUpdate — true/null juntos é o estado quebrado; se ambos parecerem intactos, verifique getComputedStyle(cur).opacity e se ele desaparece apenas no flash do clímax |
| Fantasmas/rastros WebGL, ou cores se mesclam incorretamente contra a página | Limpeza por quadro ausente, ou incompatibilidade de alfa pré-multiplicado. roll-shader.js chama gl.clear(gl.COLOR_BUFFER_BIT) a cada quadro e cria o contexto com { alpha: true, premultipliedAlpha: false } (ambas correções de auditoria, conforme o comentário do cabeçalho v4-d). | Diff roll-shader.js contra git: git diff HEAD -- design-demos/js/roll-shader.js |
| Canvas do shader em branco, sem granulação | (a) Movimento reduzido — GL nunca é configurado intencionalmente (useGL = !Roll.reduced && setupGL()); (b) Contexto WebGL perdido — o manipulador webglcontextlost define a opacidade do canvas como 0 e falha silenciosamente; (c) Um contexto 2D foi adquirido antes do WebGL ter sua chance (um contexto por canvas, sempre — documentado no topo de roll-shader.js). | Roll.reduced primeiro. Para perda de contexto, verifique o efeito observável do manipulador: getComputedStyle(document.getElementById('tone')).opacity === '0'. Caveat: Roll.shader.useGL é um snapshot do momento da configuração (roll-shader.js:120-121) — o manipulador webglcontextlost altera apenas a variável de closure (roll-shader.js:130-132), então Roll.shader.useGL permanece true após a perda de contexto; não use isso para descartar a perda |
| Coreografia de rolagem morta, mas a página renderiza e rola bem | Ordem de carregamento de script ou quebra do namespace window.Roll. A ordem dos scripts é crucial — a cadeia e os comandos de verificação vivem em pryne-frontend-architecture. Cada módulo é uma IIFE que compartilha estado apenas via window.Roll; um erro lançado em um módulo inicial mata tudo depois dele. | Experimento 2 abaixo; o console mostrará Roll.X is undefined nomeando o módulo que morreu de fome |
| Todo movimento morto para um relatório de usuário; funciona bem na sua máquina | prefers-reduced-motion está ativo para eles. Isso é comportamento correto, não um bug: roll-core.js define Roll.reduced a partir da media query, e cada módulo bloqueia com base nisso (cover removido, placas renderizam totalmente desenvolvidas instantaneamente, Lenis pulado, shader desligado). Não "corrija" isso. | Experimento 3 abaixo |
| Sensação de rolagem inconsistente entre trackpad/roda/toque | Variação bruta do delta de rolagem — a justificativa documentada para vender Lenis (veja design-demos/DECISIONS.md). Lenis envolve a rolagem nativa, então window.scrollY permanece válido; é apenas uma melhoria de sensação, nula sob movimento reduzido. | typeof Lenis (carregado?), então verifique se a demo o constrói em seu módulo de rolagem |
| Funcionamento básico funciona, mas polimento hover/kinético/cursor está faltando | GSAP CDN falhou ou foi bloqueado. GSAP carrega async do jsdelivr (fixado com SRI) e altera Roll.enhanced = true via Roll.upgradeMotion() somente quando chega. O aprimoramento progressivo é por design: a coreografia básica deve funcionar sem ele. Se o básico também estiver quebrado, esta não é sua causa. | Experimento 4 abaixo |
| Áudio silencioso | Mudo é o padrão: roll-audio.js começa mudo, persiste a escolha em localStorage['ch001_muted'], e só inicia o zumbido ambiente a partir do clique em #mute-toggle (um gesto do usuário, satisfazendo a política de reprodução automática). Toda síntese é encapsulada em try/catch e sem ativos. Verifique o estado do botão SND antes de suspeitar do código. | Roll.audio.muted, e localStorage.getItem('ch001_muted') |
| HUD fixo sobrepõe/obscurece o rodapé | Regressão da correção de desvanecimento do rodapé: um IntersectionObserver no footer alterna .faded no medidor de batidas e no botão mudo (roll-scroll.js). | Role até o rodapé; verifique se .faded aparece em #beatmeter |
Experimentos discriminadores
Execute estes no console da página ou via evaluate_script (veja pryne-browser-lab). Cada um responde a uma pergunta antes de você tocar no código.
1 — O desenvolvimento da placa está corretamente bloqueado na visibilidade?
({ workVisible: document.getElementById('work').classList.contains('in'),
plate1: { d: Roll.featurePlate.d, done: !!Roll.featurePlate.done },
plate2: { d: Roll.featurePlate2.d, done: !!Roll.featurePlate2.done } })
Em um carregamento novo, antes de rolar para a seção de trabalho: workVisible: false e ambos os valores d próximos de 0. Se d estiver subindo (ou done: true) enquanto workVisible é false, o bloqueio regrediu.
2 — A espinha dorsal do Roll está intacta?
({ core: !!window.Roll, reduced: Roll?.reduced, enhanced: Roll?.enhanced,
shader: !!Roll?.shader, audio: !!Roll?.audio, plates: !!Roll?.plates,
cursorUpdate: Roll?.cursorUpdate === null ? 'null' : typeof Roll?.cursorUpdate })
Nota sobre cursorUpdate: é inicializado como null (roll-core.js:23) e também é null antes do GSAP carregar e em dispositivos não pointer: fine — null sozinho não prova nada. "Falha segura" é indicada apenas quando document.body.classList.contains('custom-cursor') é true e cursorUpdate é null (veja a linha do cursor na tabela de triagem).
Qualquer false/undefined nomeia o módulo que não terminou — verifique o console para o erro que lançou e verifique a ordem dos scripts no HTML contra a ordem de carregamento acima.
3 — "Todo movimento morto" é apenas movimento reduzido?
({ mediaQuery: matchMedia('(prefers-reduced-motion: reduce)').matches, roll: Roll.reduced })
Ambos true → funcionando como projetado; reproduza o relatório emulando movimento reduzido (pryne-browser-lab). mediaQuery: true mas roll: false (ou vice-versa) → um módulo está lendo a fonte de verdade errada.
4 — A camada de aprimoramento GSAP carregou?
({ gsapLoaded: !!window.gsap, enhanced: Roll.enhanced, reduced: Roll.reduced })
gsapLoaded: false → CDN bloqueado/falhou (verifique o painel de rede para a requisição jsdelivr; incompatibilidade de SRI também cai aqui). gsapLoaded: true, enhanced: false, reduced: false → upgradeMotion() não executou — verifique o gancho onload da tag de script.
Armadilhas que custam tempo real
| Armadilha | A história (uma linha) | A cerca |
|---|---|---|
| "Verificado funcionando" ≠ direção certa | v3 NIGHT DRIVE estava totalmente construído, zero erros de console, verificado — depois substituído porque o conceito unificador estava errado (conta completa: pryne-failure-archaeology). | Não gaste esforço de polimento/depuração defendendo uma compilação cujo conceito não foi confirmado como a direção atual. Verifique DECISIONS.md e o status do vault primeiro. |
| Rediagnosticar uma correção documentada | Cada comentário do cabeçalho v4 é um changelog de defeitos já encontrados e já corrigidos. | Leia o comentário do cabeçalho antes de abrir devtools. Se uma correção listada parecer quebrada, procure a reversão, não o sintoma. |
| "Corrigir" movimento reduzido | Todo movimento desligado é o comportamento projetado para usuários de prefers-reduced-motion, bloqueado em um lugar (Roll.reduced). | Execute o experimento 3 antes de tratar um relatório de sem movimento como um defeito. |
| Adquirir um contexto 2D "para testar algo" | Um canvas só pode ter um tipo de contexto; pegar 2D primeiro torna o WebGL impossível naquele canvas para sempre (documentado em roll-shader.js). | Nunca chame getContext('2d') em #tone em experimentos de console. |
Quando NÃO usar este skill
- Disciplina de depuração genérica (hipóteses, mudanças mínimas, causa raiz antes da correção) → superpowers:systematic-debugging.
- Como dirigir o navegador/medir (anatomia da ferramenta MCP, rastreamentos, Lighthouse, capturas de tela) → pryne-browser-lab.
- Decidir se o comportamento viola uma invariante de design (bloqueio de movimento reduzido, personalidade em nível de sussurro, venda) → pryne-frontend-architecture.
- A história completa de por que algo foi construído/revertido → pryne-failure-archaeology.
- Outras pilhas (React/complicações de framework, projetos não Pryne): a tabela acima é específica para a família de demonstrações
window.Roll; apenas a disciplina genérica é transferível.
Proveniência e manutenção
Execute scripts/verify.sh (no diretório deste skill) para verificar tudo abaixo de uma vez.
Fatos atuais em 22/07/2026, verificados contra o repositório ~/Documents/Coding Folder/Portfolio (test) no commit 457868a. Re-verifique antes de confiar:
- Lista de módulos e tamanhos:
wc -l design-demos/js/*.js - Ordem de carregamento de scripts:
grep -n "<script" design-demos/v4-d-hybrid.html - Quais demos usam os módulos compartilhados:
grep -l "roll-core.js" design-demos/*.html - Convenção de comentário do cabeçalho ainda válida:
for f in design-demos/v4-*.html; do echo "== $f"; head -5 "$f"; done - Portão de movimento reduzido:
grep -n "prefers-reduced-motion\|Roll.reduced" design-demos/js/*.js - Bloqueio de visibilidade da placa:
grep -n "classList.contains('in')" design-demos/js/roll-scroll.js - Lenis vendido e conectado:
ls design-demos/js/vendor/ && grep -n "new Lenis" design-demos/js/roll-scroll.js - Gancho de aprimoramento GSAP:
grep -n "upgradeMotion" design-demos/js/roll-core.js design-demos/v4-d-hybrid.html - Padrão de mudo de áudio e chave de armazenamento:
grep -n "ch001_muted" design-demos/js/roll-audio.js - Barra de zero erros de console:
grep -n "console errors" design-demos/DECISIONS.md