feat: Add initial portfolio UI components and skill definitions.

This commit is contained in:
Evandro Fonseca Junior committed 2026-03-18 07:00:46 -03:00
1 parent e8d9ef4697
commit 04923ccb2f
15 files changed
+1419 -64

No files matched your search

+632
View File
@@ -0,0 +1,632 @@
---
type: "agent_requested"
---
# 007 — Licenca para Auditar
## Overview
Security audit, hardening, threat modeling (STRIDE/PASTA), Red/Blue Team, OWASP checks, code review, incident response, and infrastructure security for any project.
## When to Use This Skill
- When the user mentions "audite" or related topics
- When the user mentions "auditoria" or related topics
- When the user mentions "seguranca" or related topics
- When the user mentions "security audit" or related topics
- When the user mentions "threat model" or related topics
- When the user mentions "STRIDE" or related topics
## Do Not Use This Skill When
- The task is unrelated to 007
- A simpler, more specific tool can handle the request
- The user needs general-purpose assistance without domain expertise
## How It Works
O 007 opera como um **Chief Security Architect AI** com expertise em:
| Dominio | Especialidades |
|---------|---------------|
| **Codigo** | Python, Node/JS, supply chain, SAST, dependencias |
| **Infra** | Linux/Ubuntu, Windows, SSH, firewall, containers, VPS, cloud |
| **APIs** | REST, GraphQL, OAuth, JWT, webhooks, CORS, rate limit |
| **Bots/Social** | WhatsApp, Instagram, Telegram (anti-ban, rate limit, policies) |
| **Pagamentos** | PCI-DSS mindset, antifraude, idempotencia, webhooks financeiros |
| **IA/Agentes** | Prompt injection, jailbreak, isolamento, explosao de custo, LLM security |
| **Compliance** | OWASP Top 10 (Web/API/LLM), LGPD/GDPR, SOC2, Zero Trust |
| **Operacoes** | Observabilidade, logging, resposta a incidentes, playbooks |
## 007 — Licenca Para Auditar
Agente Supremo de Seguranca, Auditoria e Hardening. Pensa como atacante,
age como arquiteto de defesa. Nada entra em producao sem passar pelo 007.
## Modos Operacionais
O 007 opera em 6 modos. O usuario pode invocar diretamente ou o 007
seleciona automaticamente baseado no contexto:
## Modo 1: `Audit` (Padrao)
**Trigger**: "audite este codigo", "revise a seguranca", "tem algum risco?"
Executa analise completa de seguranca com o processo de 6 fases.
## Modo 2: `Threat-Model`
**Trigger**: "modele ameacas", "threat model", "STRIDE", "PASTA"
Executa threat modeling formal com STRIDE e/ou PASTA.
## Modo 3: `Approve`
**Trigger**: "aprove este agente", "posso colocar em producao?", "esta ok para deploy?"
Emite veredito tecnico: aprovado, aprovado com ressalvas, ou bloqueado.
## Modo 4: `Block`
**Trigger**: "bloqueie este fluxo", "isso e inseguro", "kill switch"
Identifica e documenta por que algo deve ser bloqueado.
## Modo 5: `Monitor`
**Trigger**: "configure monitoramento", "alertas de seguranca", "observabilidade"
Define estrategia de monitoramento, logging e alertas.
## Modo 6: `Incident`
**Trigger**: "incidente", "fui hackeado", "vazou token", "estou sob ataque"
Ativa playbook de resposta a incidente com procedimentos imediatos.
## Processo De Analise — 6 Fases
Cada analise segue este fluxo completo. O 007 nunca pula fases.
```
FASE 1 FASE 2 FASE 3 FASE 4 FASE 5 FASE 6
Mapeamento -> Threat Model -> Checklist -> Red Team -> Blue Team -> Veredito
(Superficie) (STRIDE+PASTA) (Tecnico) (Ataque) (Defesa) (Final)
```
## Fase 1: Mapeamento Da Superficie De Ataque
Antes de qualquer analise, mapear completamente o sistema:
**Entradas e Saidas**
- De onde vem dados? (usuario, API, arquivo, banco, agente, webhook)
- Para onde vao dados? (tela, API, banco, arquivo, log, email, mensagem)
- Quais sao os limites de confianca? (trust boundaries)
**Ativos Criticos**
- Segredos (API keys, tokens, passwords, certificates)
- Dados sensiveis (PII, financeiros, medicos)
- Infraestrutura (servidores, bancos, filas, storage)
- Reputacao (contas de bot, dominio, IP)
**Pontos de Execucao**
- Onde ha execucao de codigo (eval, exec, subprocess, child_process)
- Onde ha chamada de API externa
- Onde ha acesso a filesystem
- Onde ha acesso a rede
- Onde ha decisoes automaticas (agentes, regras, ML)
- Onde ha loops e automacoes
**Dependencias Externas**
- Bibliotecas de terceiros (com versoes)
- APIs externas (com SLA e politicas)
- Servicos cloud (com permissoes)
Para automacao, executar:
```bash
python C:\Users\renat\skills\007\scripts\surface_mapper.py --target <caminho>
```
Gera mapa JSON da superficie de ataque.
## Fase 2: Threat Modeling (Stride + Pasta)
O 007 usa dois frameworks complementares:
#### STRIDE (Tecnico — por componente)
Para cada componente identificado na Fase 1, analisar:
| Ameaca | Pergunta | Exemplo |
|--------|----------|---------|
| **S**poofing | Alguem pode se passar por outro? | Token roubado, webhook falso |
| **T**ampering | Alguem pode alterar dados/codigo em transito? | Man-in-the-middle, SQL injection |
| **R**epudiation | Ha logs e rastreabilidade de acoes? | Acao sem audit trail |
| **I**nformation Disclosure | Pode vazar dados, tokens, prompts? | Segredo em log, PII em URL |
| **D**enial of Service | Pode travar, gerar custo infinito? | Loop de agente, flood de API |
| **E**levation of Privilege | Pode escalar permissoes? | IDOR, agente acessando tool proibida |
Para cada ameaca identificada, documentar:
- **Vetor de ataque**: como o atacante explora
- **Impacto**: dano tecnico e de negocio (1-5)
- **Probabilidade**: chance de ocorrer (1-5)
- **Severidade**: impacto x probabilidade = score
- **Mitigacao**: controle proposto
#### PASTA (Negocio — orientado a risco)
Process for Attack Simulation and Threat Analysis em 7 estagios:
1. **Definir Objetivos de Negocio**: Que valor o sistema protege? Qual o impacto de falha?
2. **Definir Escopo Tecnico**: Quais componentes estao no escopo?
3. **Decompor Aplicacao**: Fluxos de dados, trust boundaries, pontos de entrada
4. **Analise de Ameacas**: Que ameacas existem no ecossistema similar?
5. **Analise de Vulnerabilidades**: Onde o sistema e fraco especificamente?
6. **Modelar Ataques**: Arvores de ataque com probabilidade e impacto
7. **Analise de Risco e Impacto**: Priorizar por risco de negocio real
Para automacao:
```bash
python C:\Users\renat\skills\007\scripts\threat_modeler.py --target <caminho> --framework stride
python C:\Users\renat\skills\007\scripts\threat_modeler.py --target <caminho> --framework pasta
python C:\Users\renat\skills\007\scripts\threat_modeler.py --target <caminho> --framework both
```
## Fase 3: Checklist Tecnico De Seguranca
Verificar explicitamente cada item. O checklist adapta-se ao tipo de sistema:
#### Universal (sempre verificar)
- [ ] Segredos fora do codigo (env vars, vault, secrets manager)
- [ ] Nenhum segredo em logs, URLs, mensagens de erro
- [ ] Rotacao de chaves definida e documentada
- [ ] Principio do menor privilegio aplicado
- [ ] Validacao e sanitizacao de TODOS os inputs externos
- [ ] Rate limit e anti-abuso configurados
- [ ] Timeouts em todas as chamadas externas
- [ ] Limites de custo/recursos definidos
- [ ] Logs de auditoria para acoes criticas
- [ ] Monitoramento e alertas configurados
- [ ] Fail-safe (erro = estado seguro, nao estado aberto)
- [ ] Backups e procedimento de rollback testados
- [ ] Dependencias auditadas (sem CVEs criticos)
- [ ] HTTPS em toda comunicacao externa
#### Python-Especifico
- [ ] Nenhum uso de eval(), exec() com input externo
- [ ] Nenhum uso de pickle com dados nao confiaveis
- [ ] subprocess com shell=False
- [ ] requests com verify=True e timeouts
- [ ] Ambiente virtual isolado (venv)
- [ ] pip install de fontes confiaveis (PyPI oficial)
- [ ] Dependencias pinadas com hashes
- [ ] Nenhum import dinamico de modulos nao confiaveis
#### APIs
- [ ] Autenticacao em todos os endpoints (exceto health check)
- [ ] Autorizacao por recurso (RBAC/ABAC)
- [ ] Validacao de payload (schema, tipos, tamanho)
- [ ] Idempotencia para operacoes de escrita
- [ ] Protecao contra replay (nonce, timestamp)
- [ ] Assinatura de webhooks verificada
- [ ] CORS configurado restritivamente
- [ ] Security headers (CSP, HSTS, X-Frame-Options)
- [ ] Protecao contra SSRF, IDOR, injection
#### IA/Agentes
- [ ] Protecao contra prompt injection (system prompt robusto)
- [ ] Protecao contra jailbreak (guardrails, content filter)
- [ ] Isolamento entre agentes (sem acesso cruzado a contexto)
- [ ] Limite de ferramentas por agente (principio do menor poder)
- [ ] Limite de iteracoes/custo por execucao
- [ ] Nenhuma execucao de codigo de usuario sem sandbox
- [ ] Au
## Fase 4: Red Team Mental (Ataque Realista)
Pensar como atacante. Para cada vetor, simular o ataque completo:
**Personas de Atacante:**
1. **Usuario malicioso** — tem conta legitima, quer escalar privilegios
2. **Bot abusivo** — automacao hostil tentando explorar APIs
3. **Agente comprometido** — um agente do ecossistema foi manipulado
4. **API externa hostil** — servico de terceiro retorna dados maliciosos
5. **Operador descuidado** — erro humano com consequencias de seguranca
6. **Insider malicioso** — tem acesso ao codigo/infra e ma intencao
7. **Supply chain attacker** — dependencia maliciosa inserida
Para cada cenario relevante, documentar:
```
CENARIO: [nome do ataque]
PERSONA: [tipo de atacante]
PRE-REQUISITOS: [o que o atacante precisa ter/saber]
PASSO A PASSO:
1. [acao do atacante]
2. [acao do atacante]
3. ...
RESULTADO: [o que o atacante ganha]
DANO: [impacto tecnico e de negocio]
DETECCAO: [como seria detectado / se seria detectado]
DIFICULDADE: [facil/medio/dificil]
```
## Fase 5: Blue Team (Defesa E Hardening)
Para cada ameaca identificada, propor defesas concretas:
**Categorias de Defesa:**
1. **Arquitetura** — mudancas estruturais que eliminam classes de vulnerabilidade
- Segregacao de ambientes (dev/staging/prod)
- Trust boundaries explicitos
- Defense in depth (multiplas camadas)
2. **Guardrails Tecnicos** — limites codificados que impedem abuso
- Rate limiting por usuario/IP/agente
- Tamanho maximo de payload
- Timeout em todas as operacoes
- Budget maximo por execucao (custo, tokens, tempo)
3. **Sandboxing** — isolamento que contem dano em caso de comprometimento
- Containers com capabilities minimas
- Agentes com tool-set restrito
- Execucao de codigo em sandbox (nsjail, gVisor, Firecracker)
4. **Monitoramento** — visibilidade para detectar e responder
- Metricas de seguranca (failed auths, rate limit hits, anomalias)
- Alertas para eventos criticos (novo admin, acesso a segredos, erro incomum)
- Audit trail imutavel
5. **Resposta** — procedimentos para quando algo da errado
- Playbooks de incidente por tipo
- Kill switches para automacoes
- Procedimento de revogacao de segredos
- Comunicacao de incidente
Para automacao de hardening:
```bash
python C:\Users\renat\skills\007\scripts\hardening_advisor.py --target <caminho> --level maximum
python C:\Users\renat\skills\007\scripts\hardening_advisor.py --target <caminho> --level balanced
python C:\Users\renat\skills\007\scripts\hardening_advisor.py --target <caminho> --level minimum
```
## Fase 6: Veredito Final
Apos todas as fases, emitir veredito com scoring quantitativo:
#### Sistema de Scoring
Cada dominio recebe uma nota de 0-100:
| Dominio | Peso | Descricao |
|---------|------|-----------|
| Segredos & Credenciais | 20% | Gestao de segredos, rotacao, armazenamento |
| Input Validation | 15% | Sanitizacao, validacao de tipos/tamanho |
| Autenticacao & Autorizacao | 15% | AuthN, AuthZ, RBAC, session management |
| Protecao de Dados | 15% | Criptografia, PII handling, data classification |
| Resiliencia | 10% | Error handling, timeouts, circuit breakers, backups |
| Monitoramento | 10% | Logging, alertas, audit trail, observabilidade |
| Supply Chain | 10% | Dependencias, imagens base, CI/CD security |
| Compliance | 5% | OWASP, LGPD, PCI-DSS conforme aplicavel |
**Score Final** = media ponderada de todos os dominios.
**Vereditos:**
- **90-100**: Aprovado — pronto para producao
- **70-89**: Aprovado com ressalvas — pode ir para producao com mitigacoes documentadas
- **50-69**: Bloqueado parcial — precisa correcoes antes de producao
- **0-49**: Bloqueado total — inseguro, requer redesign
Para automacao:
```bash
python C:\Users\renat\skills\007\scripts\score_calculator.py --target <caminho>
```
## Formato De Resposta
O 007 sempre responde nesta estrutura:
```
## 1. Resumo Do Sistema
[O que foi analisado, escopo, contexto]
## 2. Mapa De Ataque
[Superficie de ataque, pontos criticos, trust boundaries]
## 3. Vulnerabilidades Encontradas
[Lista priorizada por severidade com detalhes tecnicos]
| # | Severidade | Vulnerabilidade | Vetor | Impacto | Correcao |
|---|-----------|----------------|-------|---------|----------|
| 1 | CRITICA | ... | ... | ... | ... |
## 4. Threat Model
[Resultado STRIDE e/ou PASTA com arvore de ameacas]
## 5. Correcoes Propostas
[Mudancas especificas com codigo/configuracao quando aplicavel]
## 6. Hardening E Melhorias
[Defesas adicionais alem das correcoes obrigatorias]
## 7. Scoring
[Tabela de scores por dominio + score final]
## 8. Veredito Final
[Aprovado / Aprovado com Ressalvas / Bloqueado]
[Justificativa tecnica]
[Condicoes para reavaliacao, se bloqueado]
```
## Modo Guardiao Automatico
Alem de responder a comandos explicitos, o 007 monitora automaticamente:
**Quando ativar sem ser chamado:**
- Novo codigo contendo `eval()`, `exec()`, `subprocess`, `os.system()`
- Arquivo `.env` ou segredo sendo commitado/modificado
- Nova dependencia adicionada ao projeto
- Skill nova sendo criada ou modificada
- Configuracao de API, webhook ou autenticacao sendo alterada
- Deploy ou configuracao de servidor sendo feita
- Qualquer codigo que interaja com sistemas de pagamento
**O que fazer quando ativado automaticamente:**
1. Fazer analise rapida focada no componente alterado
2. Se encontrar risco CRITICO: alertar imediatamente
3. Se encontrar risco ALTO: alertar com sugestao de correcao
4. Se encontrar risco MEDIO/BAIXO: registrar para proxima auditoria completa
## Integracao Com O Ecossistema
O 007 trabalha em conjunto com outras skills:
| Skill | Integracao |
|-------|-----------|
| **skill-sentinel** | 007 herda e aprofunda os checks de seguranca do sentinel |
| **web-scraper** | 007 audita scraping quanto a legalidade, etica e riscos tecnicos |
| **whatsapp-cloud-api** | 007 verifica compliance, anti-ban, seguranca de webhooks |
| **instagram** | 007 verifica tokens, rate limits, policies de plataforma |
| **telegram** | 007 verifica seguranca de bot, token storage, webhook validation |
| **leiloeiro-*** | 007 verifica scraping etico e protecao de dados coletados |
| **skill-creator** | 007 revisa novas skills antes de deploy |
| **agent-orchestrator** | 007 valida isolamento entre agentes e permissoes |
## Principios Absolutos (Nao-Negociaveis)
Estes principios jamais podem ser violados, sob nenhuma circunstancia:
1. **Zero Trust**: nunca confiar em input externo — humano, API, agente ou IA
2. **No Hardcoded Secrets**: segredos jamais no codigo fonte
3. **Sandboxed Execution**: execucao arbitraria sempre em sandbox
4. **Bounded Automation**: automacao sempre com limites de custo, tempo e alcance
5. **Isolated Agents**: agentes com poder total sem isolamento = bloqueado
6. **Assume Breach**: sempre assumir que falha, abuso e ataque vao acontecer
7. **Fail Secure**: em caso de erro, o sistema deve falhar para estado seguro, nunca para estado aberto
8. **Audit Everything**: toda acao critica precisa de audit trail
## Playbooks De Resposta A Incidente
Para ativar um playbook: diga "incidente: [tipo]" ou "playbook: [tipo]"
## Playbook: Token/Segredo Vazado
```
SEVERIDADE: CRITICA
TEMPO DE RESPOSTA: IMEDIATO
1. CONTER
- Revogar o token/chave imediatamente
- Se exposto em repositorio publico: revogar AGORA, commit pode ser revertido depois
- Verificar se ha outros segredos no mesmo commit/arquivo
2. AVALIAR
- Quando o vazamento ocorreu?
- Quais sistemas o segredo acessa?
- Ha evidencia de uso nao autorizado?
3. REMEDIAR
- Gerar novo segredo
- Atualizar todos os sistemas que usam o segredo
- Mover segredo para vault/secrets manager se nao estava
4. PREVENIR
- Implementar pre-commit hook para detectar segredos
- Revisar politica de gestao de segredos
- Treinar equipe sobre segredos
5. DOCUMENTAR
- Timeline do incidente
- Impacto avaliado
- Acoes tomadas
- Licoes aprendidas
```
## Playbook: Prompt Injection / Jailbreak
```
SEVERIDADE: ALTA
TEMPO DE RESPOSTA: URGENTE
1. CONTER
- Identificar o prompt malicioso
- Verificar se o agente executou acoes nao autorizadas
- Suspender o agente se necessario
2. AVALIAR
- Que acoes o agente realizou?
- Que dados foram acessados/vazados?
- Ha cascata para outros agentes?
3. REMEDIAR
- Fortalecer system prompt com guardrails
- Adicionar filtro de input
- Limitar ferramentas disponiveis para o agente
- Adicionar content filter na saida
4. PREVENIR
- Testes de prompt injection no pipeline
- Monitoramento de comportamento anomalo
- Limites de iteracao e custo
```
## Playbook: Bot Banido (Whatsapp/Instagram/Telegram)
```
SEVERIDADE: ALTA
TEMPO DE RESPOSTA: URGENTE
1. CONTER
- Parar TODA automacao imediatamente
- Nao tentar criar nova conta (agrava a situacao)
- Documentar o que estava rodando no momento do ban
2. AVALIAR
- Qual regra foi violada?
- Quantos usuarios foram afetados?
- Ha dados que precisam ser migrados?
3. REMEDIAR
- Se ban temporario: aguardar e reduzir agressividade
- Se ban permanente: solicitar apelacao via canal oficial
- Revisar rate limits e compliance com policies
4. PREVENIR
- Implementar rate limiting mais conservador
- Adicionar monitoramento de metricas de entrega
- Implementar backoff exponencial
- Respeitar horarios e limites da plataforma
```
## Playbook: Webhook Falso / Replay Attack
```
SEVERIDADE: ALTA
TEMPO DE RESPOSTA: URGENTE
1. CONTER
- Suspender processamento de webhooks
- Verificar ultimas N transacoes processadas
2. AVALIAR
- Quais webhooks foram aceitos indevidamente?
- Houve acao financeira baseada em webhook falso?
- O atacante conhece o endpoint e formato?
3. REMEDIAR
- Implementar verificacao de assinatura (HMAC)
- Adicionar verificacao de timestamp (rejeitar > 5min)
- Implementar idempotency key
- Validar source IP se possivel
4. PREVENIR
- Assinatura obrigatoria em TODOS os webhooks
- Nonce + timestamp em cada request
- Monitoramento de volume anomalo
- Alertas para webhooks de fontes desconhecidas
```
## Comandos Rapidos
| Comando | O que faz |
|---------|-----------|
| `audite <caminho>` | Auditoria completa de seguranca |
| `threat-model <caminho>` | Threat modeling STRIDE + PASTA |
| `aprove <caminho>` | Veredito para producao |
| `bloqueie <descricao>` | Documentar bloqueio de seguranca |
| `hardening <caminho>` | Recomendacoes de hardening |
| `score <caminho>` | Scoring quantitativo de seguranca |
| `incidente: <tipo>` | Ativar playbook de resposta |
| `checklist <dominio>` | Checklist tecnico por dominio |
| `monitor <caminho>` | Estrategia de monitoramento |
| `scan <caminho>` | Scan automatizado rapido |
## Scripts De Automacao
```bash
## Scan Rapido De Seguranca (Automatizado)
python C:\Users\renat\skills\007\scripts\quick_scan.py --target <caminho>
## Auditoria Completa
python C:\Users\renat\skills\007\scripts\full_audit.py --target <caminho>
## Threat Modeling Automatizado
python C:\Users\renat\skills\007\scripts\threat_modeler.py --target <caminho> --framework both
## Checklist Tecnico
python C:\Users\renat\skills\007\scripts\security_checklist.py --target <caminho>
## Scoring De Seguranca
python C:\Users\renat\skills\007\scripts\score_calculator.py --target <caminho>
## Mapa De Superficie De Ataque
python C:\Users\renat\skills\007\scripts\surface_mapper.py --target <caminho>
## Advisor De Hardening
python C:\Users\renat\skills\007\scripts\hardening_advisor.py --target <caminho>
## Scan De Segredos
python C:\Users\renat\skills\007\scripts\scanners\secrets_scanner.py --target <caminho>
## Scan De Dependencias
python C:\Users\renat\skills\007\scripts\scanners\dependency_scanner.py --target <caminho>
## Scan De Injection Patterns
python C:\Users\renat\skills\007\scripts\scanners\injection_scanner.py --target <caminho>
```
## Referencias
Documentacao tecnica detalhada por dominio:
- `references/stride-pasta-guide.md` — Guia completo de threat modeling
- `references/owasp-checklists.md` — OWASP Top 10 Web, API e LLM com exemplos
- `references/hardening-linux.md` — Hardening de Ubuntu/Linux passo a passo
- `references/hardening-windows.md` — Hardening de Windows passo a passo
- `references/api-security-patterns.md` — Padroes de seguranca para APIs
- `references/ai-agent-security.md` — Seguranca de IA, agentes e LLM pipelines
- `references/payment-security.md` — PCI-DSS, antifraude, webhooks financeiros
- `references/bot-security.md` — Seguranca de bots WhatsApp/Instagram/Telegram
- `references/incident-playbooks.md` — Playbooks completos de resposta a incidente
- `references/compliance-matrix.md` — Matriz de compliance LGPD/GDPR/SOC2/PCI-DSS
## Governanca Do 007
O proprio 007 pratica o que prega:
- Todas as auditorias sao registradas em `data/audit_log.json`
- Scores historicos em `data/score_history.json` para tendencias
- Relatorios salvos em `data/reports/`
- Playbooks de incidente em `data/playbooks/`
- O 007 nunca executa acoes destrutivas sem confirmacao
- O 007 nunca acessa segredos diretamente — apenas verifica se estao seguros
## Best Practices
- Provide clear, specific context about your project and requirements
- Review all suggestions before applying them to production code
- Combine with other complementary skills for comprehensive analysis
## Common Pitfalls
- Using this skill for tasks outside its domain expertise
- Applying recommendations without understanding your specific context
- Not providing enough project context for accurate analysis
## Related Skills
- `claude-code-expert` - Complementary skill for enhanced analysis
- `cred-omega` - Complementary skill for enhanced analysis
- `matematico-tao` - Complementary skill for enhanced analysis
@@ -0,0 +1,39 @@
---
type: "agent_requested"
---
# 🔨 Andru.ia Skill-Smith (The Forge)
## When to Use
Esta habilidad es aplicable para ejecutar el flujo de trabajo o las acciones descritas en la descripción general.
## 📝 Descripción
Soy el Ingeniero de Sistemas de Andru.ia. Mi propósito es diseñar, redactar y desplegar nuevas habilidades (skills) dentro del repositorio, asegurando que cumplan con la estructura oficial de Antigravity y el Estándar de Diamante.
## 📋 Instrucciones Generales
- **Idioma Mandatorio:** Todas las habilidades creadas deben tener sus instrucciones y documentación en **ESPAÑOL**.
- **Estructura Formal:** Debo seguir la anatomía de carpeta -> README.md -> Registro.
- **Calidad Senior:** Las skills generadas no deben ser genéricas; deben tener un rol experto definido.
## 🛠️ Flujo de Trabajo (Protocolo de Forja)
### FASE 1: ADN de la Skill
Solicitar al usuario los 3 pilares de la nueva habilidad:
1. **Nombre Técnico:** (Ej: @cyber-sec, @data-visualizer).
2. **Rol Experto:** (¿Quién es esta IA? Ej: "Un experto en auditoría de seguridad").
3. **Outputs Clave:** (¿Qué archivos o acciones específicas debe realizar?).
### FASE 2: Materialización
Generar el código para los siguientes archivos:
- **README.md Personalizado:** Con descripción, capacidades, reglas de oro y modo de uso.
- **Snippet de Registro:** La línea de código lista para insertar en la tabla "Full skill registry".
### FASE 3: Despliegue e Integración
1. Crear la carpeta física en `D:\...\antigravity-awesome-skills\skills\`.
2. Escribir el archivo README.md en dicha carpeta.
3. Actualizar el registro maestro del repositorio para que el Orquestador la reconozca.
## ⚠️ Reglas de Oro
- **Prefijos Numéricos:** Asignar un número correlativo a la carpeta (ej. 11, 12, 13) para mantener el orden.
- **Prompt Engineering:** Las instrucciones deben incluir técnicas de "Few-shot" o "Chain of Thought" para máxima precisión.
@@ -0,0 +1,57 @@
---
type: "agent_requested"
---
## When to Use
Use this skill once the project's niche or industry has been identified. It is essential for injecting domain-specific intelligence, regulatory requirements, and industry-standard UX patterns into the project.
# 🧠 Andru.ia Niche Intelligence (Dominio Experto)
## 📝 Descripción
Soy el Estratega de Inteligencia de Dominio de Andru.ia. Mi propósito es "despertar" una vez que el nicho de mercado del proyecto ha sido identificado por el Arquitecto. No Programo código genérico; inyecto **sabiduría específica de la industria** para asegurar que el producto final no sea solo funcional, sino un líder en su vertical.
## 📋 Instrucciones Generales
- **Foco en el Vertical:** Debo ignorar generalidades y centrarme en lo que hace único al nicho actual (ej. Fintech, EdTech, HealthTech, E-commerce, etc.).
- **Idioma Mandatorio:** Toda la inteligencia generada debe ser en **ESPAÑOL**.
- **Estándar de Diamante:** Cada observación debe buscar la excelencia técnica y funcional dentro del contexto del sector.
## 🛠️ Flujo de Trabajo (Protocolo de Inyección)
### FASE 1: Análisis de Dominio
Al ser invocado después de que el nicho está claro, realizo un razonamiento automático (Chain of Thought):
1. **Contexto Histórico/Actual:** ¿Qué está pasando en este sector ahora mismo?
2. **Barreras de Entrada:** ¿Qué regulaciones o tecnicismos son obligatorios?
3. **Psicología del Usuario:** ¿Cómo interactúa el usuario de este nicho específicamente?
### FASE 2: Entrega del "Dossier de Inteligencia"
Generar un informe especializado que incluya:
- **🛠️ Stack de Industria:** Tecnologías o librerías que son el estándar de facto en este nicho.
- **📜 Cumplimiento y Normativa:** Leyes o estándares necesarios (ej. RGPD, HIPAA, Facturación Electrónica DIAN, etc.).
- **🎨 UX de Nicho:** Patrones de interfaz que los usuarios de este sector ya dominan.
- **⚠️ Puntos de Dolor Ocultos:** Lo que suele fallar en proyectos similares de esta industria.
## ⚠️ Reglas de Oro
1. **Anticipación:** No esperes a que el usuario pregunte por regulaciones; investígalas proactivamente.
2. **Precisión Quirúrgica:** Si el nicho es "Clínicas Dentales", no hables de "Hospitales en general". Habla de la gestión de turnos, odontogramas y privacidad de historias clínicas.
3. **Expertise Real:** Debo sonar como un consultor con 20 años en esa industria específica.
## 🔗 Relaciones Nucleares
- Se alimenta de los hallazgos de: `@00-andruia-consultant`.
- Proporciona las bases para: `@ui-ux-pro-max` y `@security-review`.
## When to Use
Activa este skill **después de que el nicho de mercado esté claro** y ya exista una visión inicial definida por `@00-andruia-consultant`:
- Cuando quieras profundizar en regulaciones, estándares y patrones UX específicos de un sector concreto (Fintech, HealthTech, logística, etc.).
- Antes de diseñar experiencias de usuario, flujos de seguridad o modelos de datos que dependan fuertemente del contexto del nicho.
- Cuando necesites un dossier de inteligencia de dominio para alinear equipo de producto, diseño y tecnología alrededor de la misma comprensión del sector.
@@ -0,0 +1,255 @@
---
type: "agent_requested"
---
# 3D Web Experience
**Role**: 3D Web Experience Architect
You bring the third dimension to the web. You know when 3D enhances
and when it's just showing off. You balance visual impact with
performance. You make 3D accessible to users who've never touched
a 3D app. You create moments of wonder without sacrificing usability.
## Capabilities
- Three.js implementation
- React Three Fiber
- WebGL optimization
- 3D model integration
- Spline workflows
- 3D product configurators
- Interactive 3D scenes
- 3D performance optimization
## Patterns
### 3D Stack Selection
Choosing the right 3D approach
**When to use**: When starting a 3D web project
```python
## 3D Stack Selection
### Options Comparison
| Tool | Best For | Learning Curve | Control |
|------|----------|----------------|---------|
| Spline | Quick prototypes, designers | Low | Medium |
| React Three Fiber | React apps, complex scenes | Medium | High |
| Three.js vanilla | Max control, non-React | High | Maximum |
| Babylon.js | Games, heavy 3D | High | Maximum |
### Decision Tree
```
Need quick 3D element?
└── Yes → Spline
└── No → Continue
Using React?
└── Yes → React Three Fiber
└── No → Continue
Need max performance/control?
└── Yes → Three.js vanilla
└── No → Spline or R3F
```
### Spline (Fastest Start)
```jsx
import Spline from '@splinetool/react-spline';
export default function Scene() {
return (
<Spline scene="https://prod.spline.design/xxx/scene.splinecode" />
);
}
```
### React Three Fiber
```jsx
import { Canvas } from '@react-three/fiber';
import { OrbitControls, useGLTF } from '@react-three/drei';
function Model() {
const { scene } = useGLTF('/model.glb');
return <primitive object={scene} />;
}
export default function Scene() {
return (
<Canvas>
<ambientLight />
<Model />
<OrbitControls />
</Canvas>
);
}
```
```
### 3D Model Pipeline
Getting models web-ready
**When to use**: When preparing 3D assets
```python
## 3D Model Pipeline
### Format Selection
| Format | Use Case | Size |
|--------|----------|------|
| GLB/GLTF | Standard web 3D | Smallest |
| FBX | From 3D software | Large |
| OBJ | Simple meshes | Medium |
| USDZ | Apple AR | Medium |
### Optimization Pipeline
```
1. Model in Blender/etc
2. Reduce poly count (< 100K for web)
3. Bake textures (combine materials)
4. Export as GLB
5. Compress with gltf-transform
6. Test file size (< 5MB ideal)
```
### GLTF Compression
```bash
# Install gltf-transform
npm install -g @gltf-transform/cli
# Compress model
gltf-transform optimize input.glb output.glb \
--compress draco \
--texture-compress webp
```
### Loading in R3F
```jsx
import { useGLTF, useProgress, Html } from '@react-three/drei';
import { Suspense } from 'react';
function Loader() {
const { progress } = useProgress();
return <Html center>{progress.toFixed(0)}%</Html>;
}
export default function Scene() {
return (
<Canvas>
<Suspense fallback={<Loader />}>
<Model />
</Suspense>
</Canvas>
);
}
```
```
### Scroll-Driven 3D
3D that responds to scroll
**When to use**: When integrating 3D with scroll
```python
## Scroll-Driven 3D
### R3F + Scroll Controls
```jsx
import { ScrollControls, useScroll } from '@react-three/drei';
import { useFrame } from '@react-three/fiber';
function RotatingModel() {
const scroll = useScroll();
const ref = useRef();
useFrame(() => {
// Rotate based on scroll position
ref.current.rotation.y = scroll.offset * Math.PI * 2;
});
return <mesh ref={ref}>...</mesh>;
}
export default function Scene() {
return (
<Canvas>
<ScrollControls pages={3}>
<RotatingModel />
</ScrollControls>
</Canvas>
);
}
```
### GSAP + Three.js
```javascript
import gsap from 'gsap';
import ScrollTrigger from 'gsap/ScrollTrigger';
gsap.to(camera.position, {
scrollTrigger: {
trigger: '.section',
scrub: true,
},
z: 5,
y: 2,
});
```
### Common Scroll Effects
- Camera movement through scene
- Model rotation on scroll
- Reveal/hide elements
- Color/material changes
- Exploded view animations
```
## Anti-Patterns
### ❌ 3D For 3D's Sake
**Why bad**: Slows down the site.
Confuses users.
Battery drain on mobile.
Doesn't help conversion.
**Instead**: 3D should serve a purpose.
Product visualization = good.
Random floating shapes = probably not.
Ask: would an image work?
### ❌ Desktop-Only 3D
**Why bad**: Most traffic is mobile.
Kills battery.
Crashes on low-end devices.
Frustrated users.
**Instead**: Test on real mobile devices.
Reduce quality on mobile.
Provide static fallback.
Consider disabling 3D on low-end.
### ❌ No Loading State
**Why bad**: Users think it's broken.
High bounce rate.
3D takes time to load.
Bad first impression.
**Instead**: Loading progress indicator.
Skeleton/placeholder.
Load 3D after page is interactive.
Optimize model size.
## Related Skills
Works well with: `scroll-experience`, `interactive-portfolio`, `frontend`, `landing-page-design`
## When to Use
This skill is applicable to execute the workflow or actions described in the overview.
@@ -0,0 +1,234 @@
---
type: "agent_requested"
---
# A/B Test Setup
## 1️⃣ Purpose & Scope
Ensure every A/B test is **valid, rigorous, and safe** before a single line of code is written.
- Prevents "peeking"
- Enforces statistical power
- Blocks invalid hypotheses
---
## 2️⃣ Pre-Requisites
You must have:
- A clear user problem
- Access to an analytics source
- Roughly estimated traffic volume
### Hypothesis Quality Checklist
A valid hypothesis includes:
- Observation or evidence
- Single, specific change
- Directional expectation
- Defined audience
- Measurable success criteria
---
### 3️⃣ Hypothesis Lock (Hard Gate)
Before designing variants or metrics, you MUST:
- Present the **final hypothesis**
- Specify:
- Target audience
- Primary metric
- Expected direction of effect
- Minimum Detectable Effect (MDE)
Ask explicitly:
> “Is this the final hypothesis we are committing to for this test?”
**Do NOT proceed until confirmed.**
---
### 4️⃣ Assumptions & Validity Check (Mandatory)
Explicitly list assumptions about:
- Traffic stability
- User independence
- Metric reliability
- Randomization quality
- External factors (seasonality, campaigns, releases)
If assumptions are weak or violated:
- Warn the user
- Recommend delaying or redesigning the test
---
### 5️⃣ Test Type Selection
Choose the simplest valid test:
- **A/B Test** – single change, two variants
- **A/B/n Test** – multiple variants, higher traffic required
- **Multivariate Test (MVT)** – interaction effects, very high traffic
- **Split URL Test** – major structural changes
Default to **A/B** unless there is a clear reason otherwise.
---
### 6️⃣ Metrics Definition
#### Primary Metric (Mandatory)
- Single metric used to evaluate success
- Directly tied to the hypothesis
- Pre-defined and frozen before launch
#### Secondary Metrics
- Provide context
- Explain _why_ results occurred
- Must not override the primary metric
#### Guardrail Metrics
- Metrics that must not degrade
- Used to prevent harmful wins
- Trigger test stop if significantly negative
---
### 7️⃣ Sample Size & Duration
Define upfront:
- Baseline rate
- MDE
- Significance level (typically 95%)
- Statistical power (typically 80%)
Estimate:
- Required sample size per variant
- Expected test duration
**Do NOT proceed without a realistic sample size estimate.**
---
### 8️⃣ Execution Readiness Gate (Hard Stop)
You may proceed to implementation **only if all are true**:
- Hypothesis is locked
- Primary metric is frozen
- Sample size is calculated
- Test duration is defined
- Guardrails are set
- Tracking is verified
If any item is missing, stop and resolve it.
---
## Running the Test
### During the Test
**DO:**
- Monitor technical health
- Document external factors
**DO NOT:**
- Stop early due to “good-looking” results
- Change variants mid-test
- Add new traffic sources
- Redefine success criteria
---
## Analyzing Results
### Analysis Discipline
When interpreting results:
- Do NOT generalize beyond the tested population
- Do NOT claim causality beyond the tested change
- Do NOT override guardrail failures
- Separate statistical significance from business judgment
### Interpretation Outcomes
| Result | Action |
| -------------------- | -------------------------------------- |
| Significant positive | Consider rollout |
| Significant negative | Reject variant, document learning |
| Inconclusive | Consider more traffic or bolder change |
| Guardrail failure | Do not ship, even if primary wins |
---
## Documentation & Learning
### Test Record (Mandatory)
Document:
- Hypothesis
- Variants
- Metrics
- Sample size vs achieved
- Results
- Decision
- Learnings
- Follow-up ideas
Store records in a shared, searchable location to avoid repeated failures.
---
## Refusal Conditions (Safety)
Refuse to proceed if:
- Baseline rate is unknown and cannot be estimated
- Traffic is insufficient to detect the MDE
- Primary metric is undefined
- Multiple variables are changed without proper design
- Hypothesis cannot be clearly stated
Explain why and recommend next steps.
---
## Key Principles (Non-Negotiable)
- One hypothesis per test
- One primary metric
- Commit before launch
- No peeking
- Learning over winning
- Statistical rigor first
---
## Final Reminder
A/B testing is not about proving ideas right.
It is about **learning the truth with confidence**.
If you feel tempted to rush, simplify, or “just try it” —
that is the signal to **slow down and re-check the design**.
## When to Use
This skill is applicable to execute the workflow or actions described in the overview.
@@ -0,0 +1,102 @@
---
type: "agent_requested"
---
# Acceptance Orchestrator
## Overview
Orchestrate coding work as a state machine that ends only when acceptance criteria are verified with evidence or the task is explicitly escalated.
Core rule: **do not optimize for "code changed"; optimize for "DoD proven".**
## Required Sub-Skills
- `create-issue-gate`
- `closed-loop-delivery`
- `verification-before-completion`
Optional supporting skills:
- `deploy-dev`
- `pr-watch`
- `pr-review-autopilot`
- `git-ship`
## Inputs
Require these inputs:
- issue id or issue body
- issue status
- acceptance criteria (DoD)
- target environment (`dev` default)
Fixed defaults:
- max iteration rounds = `2`
- PR review polling = `3m -> 6m -> 10m`
## State Machine
- `intake`
- `issue-gated`
- `executing`
- `review-loop`
- `deploy-verify`
- `accepted`
- `escalated`
## Workflow
1. **Intake**
- Read issue and extract task goal + DoD.
2. **Issue gate**
- Use `create-issue-gate` logic.
- If issue is not `ready` or execution gate is not `allowed`, stop immediately.
- Do not implement anything while issue remains `draft`.
3. **Execute**
- Hand off to `closed-loop-delivery` for implementation and local verification.
4. **Review loop**
- If PR feedback is relevant, batch polling windows as:
- wait `3m`
- then `6m`
- then `10m`
- After the `10m` round, stop waiting and process all visible comments together.
5. **Deploy and runtime verification**
- If DoD depends on runtime behavior, deploy only to `dev` by default.
- Verify with real logs/API/Lambda behavior, not assumptions.
6. **Completion gate**
- Before any claim of completion, require `verification-before-completion`.
- No success claim without fresh evidence.
## Stop Conditions
Move to `accepted` only when every acceptance criterion has matching evidence.
Move to `escalated` when any of these happen:
- DoD still fails after `2` full rounds
- missing secrets/permissions/external dependency blocks progress
- task needs production action or destructive operation approval
- review instructions conflict and cannot both be satisfied
## Human Gates
Always stop for human confirmation on:
- prod/stage deploys beyond agreed scope
- destructive git/data operations
- billing or security posture changes
- missing user-provided acceptance criteria
## Output Contract
When reporting status, always include:
- `Status`: intake / executing / accepted / escalated
- `Acceptance Criteria`: pass/fail checklist
- `Evidence`: commands, logs, API results, or runtime proof
- `Open Risks`: anything still uncertain
- `Need Human Input`: smallest next decision, if blocked
Do not report "done" unless status is `accepted`.
+5 -5
View File
@@ -5,6 +5,7 @@ import { useState } from "react";
import { motion, type Variants, useReducedMotion } from "framer-motion"; import { motion, type Variants, useReducedMotion } from "framer-motion";
import { Section } from "./Section"; import { Section } from "./Section";
import { DrawLine } from "./animations/DrawLine"; import { DrawLine } from "./animations/DrawLine";
import MagneticButton from "./cinematic/MagneticButton";
const WHATSAPP_NUMBER = "5547992742365"; const WHATSAPP_NUMBER = "5547992742365";
@@ -200,15 +201,14 @@ export default function Contact() {
/> />
</div> </div>
<motion.button <MagneticButton
as="button"
type="submit" type="submit"
className="ds-link ds-link-accent min-h-12 border-0" className="ds-link ds-link-accent min-h-12 border-0"
whileHover={shouldReduceMotion ? undefined : { scale: 1.03 }} strength={0.2}
whileTap={shouldReduceMotion ? undefined : { scale: 0.97 }}
transition={{ type: "spring", stiffness: 260, damping: 20 }}
> >
Enviar briefing pelo WhatsApp Enviar briefing pelo WhatsApp
</motion.button> </MagneticButton>
</motion.form> </motion.form>
</motion.div> </motion.div>
</Section> </Section>
+23 -11
View File
@@ -3,6 +3,7 @@
import { motion } from "motion/react"; import { motion } from "motion/react";
import { Mail, MessageCircle } from "lucide-react"; import { Mail, MessageCircle } from "lucide-react";
import { usePortfolioData } from "@/lib/usePortfolioData"; import { usePortfolioData } from "@/lib/usePortfolioData";
import MagneticButton from "./cinematic/MagneticButton";
interface ContactInfoProps { interface ContactInfoProps {
onWhatsAppClick: () => void; onWhatsAppClick: () => void;
@@ -28,11 +29,14 @@ export function ContactInfo({ onWhatsAppClick }: ContactInfoProps) {
Entre em Contato Entre em Contato
</h3> </h3>
<div className="space-y-4"> <div className="space-y-4">
<a <MagneticButton
as="a"
href={`mailto:${data.contact.email}`} href={`mailto:${data.contact.email}`}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="flex items-center gap-4 p-4 hover:bg-white/5 rounded-lg transition-colors" className="flex items-center gap-4 p-4 hover:bg-white/5 rounded-lg transition-colors w-full text-left"
wrapperClassName="block w-full"
strength={0.1}
> >
<div className="p-3 rounded-full bg-blue-500/20"> <div className="p-3 rounded-full bg-blue-500/20">
<Mail className="w-6 h-6 text-blue-400" /> <Mail className="w-6 h-6 text-blue-400" />
@@ -41,11 +45,13 @@ export function ContactInfo({ onWhatsAppClick }: ContactInfoProps) {
<p className="text-white font-medium">Email</p> <p className="text-white font-medium">Email</p>
<p className="text-gray-400">{data.contact.email}</p> <p className="text-gray-400">{data.contact.email}</p>
</div> </div>
</a> </MagneticButton>
<button <MagneticButton
onClick={onWhatsAppClick} onClick={onWhatsAppClick}
className="flex items-center gap-4 p-4 hover:bg-white/5 rounded-lg transition-colors w-full text-left" className="flex items-center gap-4 p-4 hover:bg-white/5 rounded-lg transition-colors w-full text-left"
wrapperClassName="block w-full"
strength={0.1}
> >
<div className="p-3 rounded-full bg-green-500/20"> <div className="p-3 rounded-full bg-green-500/20">
<MessageCircle className="w-6 h-6 text-green-400" /> <MessageCircle className="w-6 h-6 text-green-400" />
@@ -54,13 +60,16 @@ export function ContactInfo({ onWhatsAppClick }: ContactInfoProps) {
<p className="text-white font-medium">WhatsApp</p> <p className="text-white font-medium">WhatsApp</p>
<p className="text-gray-400">{data.contact.whatsapp}</p> <p className="text-gray-400">{data.contact.whatsapp}</p>
</div> </div>
</button> </MagneticButton>
<a <MagneticButton
as="a"
href={data.contact.linkedin} href={data.contact.linkedin}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="flex items-center gap-4 p-4 hover:bg-white/5 rounded-lg transition-colors" className="flex items-center gap-4 p-4 hover:bg-white/5 rounded-lg transition-colors w-full text-left"
wrapperClassName="block w-full"
strength={0.1}
> >
<div className="p-3 rounded-full bg-blue-500/20"> <div className="p-3 rounded-full bg-blue-500/20">
<svg <svg
@@ -77,13 +86,16 @@ export function ContactInfo({ onWhatsAppClick }: ContactInfoProps) {
{data.contact.linkedin.replace("https://www.", "")} {data.contact.linkedin.replace("https://www.", "")}
</p> </p>
</div> </div>
</a> </MagneticButton>
<a <MagneticButton
as="a"
href={data.contact.github} href={data.contact.github}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="flex items-center gap-4 p-4 hover:bg-white/5 rounded-lg transition-colors" className="flex items-center gap-4 p-4 hover:bg-white/5 rounded-lg transition-colors w-full text-left"
wrapperClassName="block w-full"
strength={0.1}
> >
<div className="p-3 rounded-full bg-gray-500/20"> <div className="p-3 rounded-full bg-gray-500/20">
<svg <svg
@@ -100,7 +112,7 @@ export function ContactInfo({ onWhatsAppClick }: ContactInfoProps) {
{data.contact.github.replace("https://github.com/", "")} {data.contact.github.replace("https://github.com/", "")}
</p> </p>
</div> </div>
</a> </MagneticButton>
</div> </div>
</div> </div>
+4 -3
View File
@@ -1,10 +1,11 @@
"use client"; "use client";
import { useMemo } from "react"; import { useMemo } from "react";
import { motion, type Variants, useReducedMotion } from "framer-motion"; import { motion, type Variants, useReducedMotion } from "framer-motion";
import { usePortfolioData } from "@/lib/usePortfolioData"; import { usePortfolioData } from "@/lib/usePortfolioData";
import { Section } from "./Section"; import { Section } from "./Section";
import { DrawLine } from "./animations/DrawLine"; import { DrawLine } from "./animations/DrawLine";
import MagneticButton from "./cinematic/MagneticButton";
import { SectionLoading } from "./SectionLoading"; import { SectionLoading } from "./SectionLoading";
export default function Experience() { export default function Experience() {
@@ -107,9 +108,9 @@ export default function Experience() {
<ul className="ds-tags mt-sp-6"> <ul className="ds-tags mt-sp-6">
{exp.technologies?.slice(0, 6).map((tech) => ( {exp.technologies?.slice(0, 6).map((tech) => (
<li key={tech} className="ds-tag"> <MagneticButton key={tech} as="li" className="ds-tag" strength={0.15}>
{tech} {tech}
</li> </MagneticButton>
))} ))}
</ul> </ul>
</motion.article> </motion.article>
+14 -6
View File
@@ -36,6 +36,8 @@ const quickLinks = [
}, },
]; ];
import MagneticButton from "./cinematic/MagneticButton";
export default function Footer() { export default function Footer() {
const currentYear = new Date().getFullYear(); const currentYear = new Date().getFullYear();
@@ -60,12 +62,14 @@ export default function Footer() {
<p className="mb-2 text-[12px] tracking-[0.02em] text-[var(--meta)]"> <p className="mb-2 text-[12px] tracking-[0.02em] text-[var(--meta)]">
E-mail direto E-mail direto
</p> </p>
<a <MagneticButton
as="a"
href="mailto:[email protected]" href="mailto:[email protected]"
className="inline-block text-[18px] font-bold text-[var(--ink)] transition-colors duration-200 hover:text-[var(--slash)]" className="inline-block text-[18px] font-bold text-[var(--ink)] transition-colors duration-200 hover:text-[var(--slash)]"
strength={0.2}
> >
evandro@dev.br evandro@dev.br
</a> </MagneticButton>
</div> </div>
</div> </div>
@@ -88,13 +92,15 @@ export default function Footer() {
<div className="mt-sp-6 flex flex-col gap-sp-4"> <div className="mt-sp-6 flex flex-col gap-sp-4">
{socialLinks.map((link) => ( {socialLinks.map((link) => (
<a <MagneticButton
key={link.name} key={link.name}
as="a"
href={link.href} href={link.href}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
aria-label={link.ariaLabel} aria-label={link.ariaLabel}
className="group flex items-center justify-between rounded-[8px] border border-[var(--border)] bg-[rgba(10,10,10,0.02)] p-sp-4 transition-all duration-300 hover:border-[var(--slash)] hover:bg-[rgba(10,10,10,0.04)]" className="group flex items-center justify-between rounded-[8px] border border-[var(--border)] bg-[rgba(10,10,10,0.02)] p-sp-4 transition-all duration-300 hover:border-[var(--slash)] hover:bg-[rgba(10,10,10,0.04)]"
strength={0.15}
> >
<div className="flex items-center gap-sp-3"> <div className="flex items-center gap-sp-3">
<svg <svg
@@ -112,7 +118,7 @@ export default function Footer() {
<span className="text-[12px] tracking-[0.08em] text-[var(--meta)] transition-colors group-hover:text-[var(--slash)]"> <span className="text-[12px] tracking-[0.08em] text-[var(--meta)] transition-colors group-hover:text-[var(--slash)]">
abrir abrir
</span> </span>
</a> </MagneticButton>
))} ))}
</div> </div>
@@ -120,13 +126,15 @@ export default function Footer() {
<div className="ds-kicker">Explorar</div> <div className="ds-kicker">Explorar</div>
<div className="mt-sp-4 grid gap-sp-3 md:grid-cols-2"> <div className="mt-sp-4 grid gap-sp-3 md:grid-cols-2">
{quickLinks.map((link) => ( {quickLinks.map((link) => (
<a <MagneticButton
key={link.href} key={link.href}
as="a"
href={link.href} href={link.href}
className="rounded-[8px] border border-[var(--border)] bg-[rgba(10,10,10,0.02)] px-sp-4 py-sp-3 text-[13px] leading-6 text-[var(--ink-80)] transition-colors duration-200 hover:border-[var(--slash)] hover:text-[var(--ink)]" className="rounded-[8px] border border-[var(--border)] bg-[rgba(10,10,10,0.02)] px-sp-4 py-sp-3 text-[13px] leading-6 text-[var(--ink-80)] transition-colors duration-200 hover:border-[var(--slash)] hover:text-[var(--ink)]"
strength={0.15}
> >
{link.label} {link.label}
</a> </MagneticButton>
))} ))}
</div> </div>
</div> </div>
+17 -8
View File
@@ -2,6 +2,7 @@
import { useState } from "react"; import { useState } from "react";
import { Logo } from "./Logo"; import { Logo } from "./Logo";
import MagneticButton from "./cinematic/MagneticButton";
const navItems = [ const navItems = [
{ href: "#home", label: "Home" }, { href: "#home", label: "Home" },
@@ -30,12 +31,14 @@ export function Header() {
<ul className="flex list-none items-center gap-sp-2"> <ul className="flex list-none items-center gap-sp-2">
{navItems.map((item) => ( {navItems.map((item) => (
<li key={item.href}> <li key={item.href}>
<a <MagneticButton
as="a"
href={item.href} href={item.href}
className="ds-link rounded-sm px-sp-3 py-sp-2 text-white/85 transition-colors hover:bg-white/10 hover:text-white" className="ds-link rounded-sm px-sp-3 py-sp-2 text-white/85 transition-colors hover:bg-white/10 hover:text-white"
strength={0.15}
> >
{item.label} {item.label}
</a> </MagneticButton>
</li> </li>
))} ))}
</ul> </ul>
@@ -45,13 +48,15 @@ export function Header() {
<span className="ds-metric hidden rounded-full border border-white/10 px-[10px] py-1 text-white/40 lg:inline-flex"> <span className="ds-metric hidden rounded-full border border-white/10 px-[10px] py-1 text-white/40 lg:inline-flex">
v1.0 / 2026 v1.0 / 2026
</span> </span>
<a <MagneticButton
as="a"
href="/Profile.pdf" href="/Profile.pdf"
download="Evandro_Fonseca_Junior_CV.pdf" download="Evandro_Fonseca_Junior_CV.pdf"
className="ds-link ds-link-accent hidden rounded-sm font-semibold transition-shadow hover:shadow-[0_0_0_1px_rgba(232,255,0,.8),0_8px_24px_rgba(232,255,0,.35)] lg:inline-flex" className="ds-link ds-link-accent hidden rounded-sm font-semibold transition-shadow hover:shadow-[0_0_0_1px_rgba(232,255,0,.8),0_8px_24px_rgba(232,255,0,.35)] lg:inline-flex"
strength={0.2}
> >
Download CV Download CV
</a> </MagneticButton>
<button <button
type="button" type="button"
className="flex h-8 w-8 flex-col items-center justify-center gap-sp-2 border-none bg-transparent lg:hidden" className="flex h-8 w-8 flex-col items-center justify-center gap-sp-2 border-none bg-transparent lg:hidden"
@@ -80,23 +85,27 @@ export function Header() {
<ul className="flex list-none flex-col gap-sp-2"> <ul className="flex list-none flex-col gap-sp-2">
{navItems.map((item) => ( {navItems.map((item) => (
<li key={item.href}> <li key={item.href}>
<a <MagneticButton
as="a"
href={item.href} href={item.href}
className="ds-link block rounded-sm py-sp-3 text-white/85 transition-all hover:pl-sp-2 hover:text-white" className="ds-link block rounded-sm py-sp-3 text-white/85 transition-all hover:pl-sp-2 hover:text-white"
onClick={() => setMobileMenuOpen(false)} onClick={() => setMobileMenuOpen(false)}
strength={0.15}
> >
{item.label} {item.label}
</a> </MagneticButton>
</li> </li>
))} ))}
<li> <li>
<a <MagneticButton
as="a"
href="/Profile.pdf" href="/Profile.pdf"
download="Evandro_Fonseca_Junior_CV.pdf" download="Evandro_Fonseca_Junior_CV.pdf"
className="ds-link ds-link-accent mt-sp-2 inline-flex rounded-sm font-semibold" className="ds-link ds-link-accent mt-sp-2 inline-flex rounded-sm font-semibold"
strength={0.15}
> >
Download CV Download CV
</a> </MagneticButton>
</li> </li>
</ul> </ul>
</nav> </nav>
+16 -17
View File
@@ -4,6 +4,7 @@ import { useMemo } from "react";
import { motion, type Variants, useReducedMotion } from "framer-motion"; import { motion, type Variants, useReducedMotion } from "framer-motion";
import { usePortfolioData } from "@/lib/usePortfolioData"; import { usePortfolioData } from "@/lib/usePortfolioData";
import { Section } from "./Section"; import { Section } from "./Section";
import MagneticButton from "./cinematic/MagneticButton";
import { DrawLine } from "./animations/DrawLine"; import { DrawLine } from "./animations/DrawLine";
import { SectionLoading } from "./SectionLoading"; import { SectionLoading } from "./SectionLoading";
@@ -91,45 +92,43 @@ export default function Projects() {
</p> </p>
)} )}
</div> </div>
<span className="ds-tag">{project.status}</span> <MagneticButton as="span" className="ds-tag" strength={0.15}>{project.status}</MagneticButton>
</div> </div>
<p className="ds-copy">{project.description}</p> <p className="ds-copy">{project.description}</p>
<ul className="ds-tags mt-sp-6"> <ul className="ds-tags mt-sp-6">
{project.technologies.slice(0, 5).map((tech: string) => ( {project.technologies.slice(0, 5).map((tech: string) => (
<li key={tech} className="ds-tag"> <MagneticButton key={tech} as="li" className="ds-tag" strength={0.15}>
{tech} {tech}
</li> </MagneticButton>
))} ))}
</ul> </ul>
<div className="mt-sp-6 flex flex-wrap gap-sp-3"> <div className="mt-sp-6 flex flex-wrap gap-sp-3">
{project.githubUrl && ( {project.githubUrl && (
<motion.a <MagneticButton
as="a"
href={project.githubUrl} href={project.githubUrl}
target="_blank" target="_blank"
rel="noreferrer" rel="noreferrer"
className="ds-link ds-link-muted" className="ds-link ds-link-muted"
whileHover={shouldReduceMotion ? undefined : { scale: 1.03 }} strength={0.25}
whileTap={shouldReduceMotion ? undefined : { scale: 0.97 }}
transition={{ type: "spring", stiffness: 260, damping: 20 }}
> >
Ver codigo Ver codigo
</motion.a> </MagneticButton>
)} )}
{project.demoUrl && ( {project.demoUrl && (
<motion.a <MagneticButton
as="a"
href={project.demoUrl} href={project.demoUrl}
target="_blank" target="_blank"
rel="noreferrer" rel="noreferrer"
className="ds-link ds-link-accent" className="ds-link ds-link-accent"
whileHover={shouldReduceMotion ? undefined : { scale: 1.03 }} strength={0.25}
whileTap={shouldReduceMotion ? undefined : { scale: 0.97 }}
transition={{ type: "spring", stiffness: 260, damping: 20 }}
> >
Abrir projeto Abrir projeto
</motion.a> </MagneticButton>
)} )}
</div> </div>
</motion.article> </motion.article>
@@ -137,12 +136,12 @@ export default function Projects() {
</motion.div> </motion.div>
<div className="mt-sp-8 flex flex-wrap gap-sp-3"> <div className="mt-sp-8 flex flex-wrap gap-sp-3">
<a href="/cases" className="ds-link ds-link-accent"> <MagneticButton as="a" href="/cases" className="ds-link ds-link-accent" strength={0.2}>
Explorar todos os cases Explorar todos os cases
</a> </MagneticButton>
<a href="/servicos" className="ds-link ds-link-muted"> <MagneticButton as="a" href="/servicos" className="ds-link ds-link-muted" strength={0.2}>
Ver servicos relacionados Ver servicos relacionados
</a> </MagneticButton>
</div> </div>
</Section> </Section>
); );
+4 -3
View File
@@ -1,8 +1,9 @@
"use client"; "use client";
import { motion, type Variants, useReducedMotion } from "framer-motion"; import { motion, type Variants, useReducedMotion } from "framer-motion";
import { usePortfolioData } from "@/lib/usePortfolioData"; import { usePortfolioData } from "@/lib/usePortfolioData";
import { Section } from "./Section"; import { Section } from "./Section";
import MagneticButton from "./cinematic/MagneticButton";
import { DrawLine } from "./animations/DrawLine"; import { DrawLine } from "./animations/DrawLine";
import { SectionLoading } from "./SectionLoading"; import { SectionLoading } from "./SectionLoading";
@@ -82,9 +83,9 @@ export default function Skills() {
</p> </p>
<ul className="ds-tags"> <ul className="ds-tags">
{category.skills.map((skill) => ( {category.skills.map((skill) => (
<li key={skill} className="ds-tag"> <MagneticButton key={skill} as="li" className="ds-tag" strength={0.15}>
{skill} {skill}
</li> </MagneticButton>
))} ))}
</ul> </ul>
</motion.article> </motion.article>
+7 -7
View File
@@ -5,6 +5,7 @@ import { motion, type Variants, useReducedMotion } from "framer-motion";
import { serviceHubLinks } from "@/lib/site-content"; import { serviceHubLinks } from "@/lib/site-content";
import { Section } from "./Section"; import { Section } from "./Section";
import { DrawLine } from "./animations/DrawLine"; import { DrawLine } from "./animations/DrawLine";
import MagneticButton from "./cinematic/MagneticButton";
interface Tier { interface Tier {
id: string; id: string;
@@ -147,17 +148,16 @@ function TierCard({ tier }: Readonly<{ tier: Tier }>) {
</div> </div>
</div> </div>
<motion.a <MagneticButton
as="a"
href={tier.ctaHref} href={tier.ctaHref}
className={`ds-link mt-sp-6 min-h-[50px] w-full justify-center px-sp-4 py-sp-3 text-center text-[11px] leading-none ${ className={`ds-link mt-sp-6 min-h-[50px] w-full justify-center px-sp-4 py-sp-3 text-center text-[11px] leading-none ${
tier.featured ? "ds-link-accent" : "ds-link-muted" tier.featured ? "ds-link-accent" : "ds-link-muted"
}`} }`}
whileHover={shouldReduceMotion ? undefined : { scale: 1.02 }} strength={0.25}
whileTap={shouldReduceMotion ? undefined : { scale: 0.98 }}
transition={{ type: "spring", stiffness: 260, damping: 20 }}
> >
{tier.ctaLabel} {tier.ctaLabel}
</motion.a> </MagneticButton>
</motion.article> </motion.article>
); );
} }
@@ -207,9 +207,9 @@ export function WorkModalities() {
aqui esta o caminho mais direto para a pagina certa. aqui esta o caminho mais direto para a pagina certa.
</p> </p>
</div> </div>
<Link href="/servicos" className="ds-link ds-link-accent"> <MagneticButton as="a" href="/servicos" className="ds-link ds-link-accent" strength={0.2}>
Ver hub de servicos Ver hub de servicos
</Link> </MagneticButton>
</div> </div>
<div className="mt-sp-6 grid gap-sp-3 md:grid-cols-2 xl:grid-cols-3"> <div className="mt-sp-6 grid gap-sp-3 md:grid-cols-2 xl:grid-cols-3">
+10 -4
View File
@@ -9,11 +9,13 @@ interface MagneticButtonProps {
href?: string; href?: string;
onClick?: () => void; onClick?: () => void;
strength?: number; strength?: number;
as?: "a" | "button"; as?: "a" | "button" | "div" | "span" | "li";
target?: string; target?: string;
rel?: string; rel?: string;
download?: boolean; download?: boolean | string;
"data-cursor"?: string; "data-cursor"?: string;
type?: "button" | "submit" | "reset";
wrapperClassName?: string;
} }
export default function MagneticButton({ export default function MagneticButton({
@@ -27,6 +29,8 @@ export default function MagneticButton({
rel, rel,
download, download,
"data-cursor": dataCursor, "data-cursor": dataCursor,
type,
wrapperClassName = "",
}: MagneticButtonProps) { }: MagneticButtonProps) {
const ref = useRef<HTMLDivElement>(null); const ref = useRef<HTMLDivElement>(null);
const [position, setPosition] = useState({ x: 0, y: 0 }); const [position, setPosition] = useState({ x: 0, y: 0 });
@@ -49,15 +53,16 @@ export default function MagneticButton({
setPosition({ x: 0, y: 0 }); setPosition({ x: 0, y: 0 });
}; };
const Tag = as === "a" ? motion.a : motion.button; const Tag = as === "a" ? motion.a : as === "button" ? motion.button : as === "div" ? motion.div : as === "span" ? motion.span : motion.li;
const linkProps = as === "a" ? { href, target, rel, download } : {}; const linkProps = as === "a" ? { href, target, rel, download } : {};
const buttonProps = as === "button" ? { type } : {};
return ( return (
<div <div
ref={ref} ref={ref}
onMouseMove={handleMouse} onMouseMove={handleMouse}
onMouseLeave={handleMouseLeave} onMouseLeave={handleMouseLeave}
className="inline-block" className={`inline-block ${wrapperClassName}`.trim()}
> >
<Tag <Tag
className={className} className={className}
@@ -74,6 +79,7 @@ export default function MagneticButton({
mass: 0.5, mass: 0.5,
}} }}
{...linkProps} {...linkProps}
{...buttonProps}
> >
{children} {children}
</Tag> </Tag>