diff --git a/.gitignore b/.gitignore
index 5ef6a52..e5b2fc4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,3 +39,16 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts
+
+# local agent/editor state
+/.augment/
+.opencode/
+.claude/settings.local.json
+.superpowers/
+
+# generated analysis artifacts
+/graphify-out/
+*.graphify.json
+*.analysis.json
+*.tmp.json
+*.debug.json
diff --git a/.graphifyignore b/.graphifyignore
new file mode 100644
index 0000000..d58fa88
--- /dev/null
+++ b/.graphifyignore
@@ -0,0 +1,21 @@
+node_modules/
+.next/
+dist/
+build/
+out/
+coverage/
+.git/
+.pnpm-store/
+.cache/
+*.log
+.env
+.env.*
+__pycache__/
+*.pyc
+.venv/
+venv/
+target/
+*.exe
+*.dll
+*.so
+*.dylib
diff --git a/README.md b/README.md
index e215bc4..8ae8c4f 100644
--- a/README.md
+++ b/README.md
@@ -1,36 +1,88 @@
-This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
+
-## Getting Started
+# Evandro Dev — Portfolio
-First, run the development server:
+**A cinematic, interactive developer portfolio built with Next.js, React, TypeScript, and motion-first UI engineering.**
-```bash
-npm run dev
-# or
-yarn dev
-# or
-pnpm dev
-# or
-bun dev
+
+
+
+
+
+
+
+
+## Overview
+
+This is the portfolio site for **Evandro Dev**. It presents professional work, case studies, technical positioning, and interactive visual storytelling through a high-polish Next.js interface.
+
+The project combines a modern App Router codebase with motion design, 3D/visual effects, and tested UI components.
+
+## Highlights
+
+| Area | Details |
+| --- | --- |
+| Framework | Next.js App Router with React and TypeScript. |
+| Motion | GSAP, Framer Motion, Lenis, and custom animation components. |
+| Visuals | Three.js / React Three Fiber / Drei for interactive and cinematic surfaces. |
+| Styling | Tailwind CSS, utility composition, and reusable component primitives. |
+| Quality | Jest, Testing Library, property-based tests, and Biome checks. |
+| Content | Portfolio sections, case pages, company logos, hero composition, and supporting docs. |
+
+## Project structure
+
+```txt
+app/
+ page.tsx Main portfolio route
+ layout.tsx Root layout and metadata
+ components/ Portfolio sections and cinematic UI modules
+ cases/ Case-study routes/content
+ api/ Server/API routes
+components/ Shared UI primitives
+lib/ Utilities and shared logic
+docs/ Supporting documentation
+graphify-out/ Project analysis output
+public/ Static assets
```
-Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
+## Getting started
-You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
+```bash
+pnpm install
+pnpm dev
+```
-This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
+The development server uses Turbopack through the project script.
-## Learn More
+## Scripts
-To learn more about Next.js, take a look at the following resources:
+| Command | Purpose |
+| --- | --- |
+| `pnpm dev` | Start the Next.js development server. |
+| `pnpm build` | Build the production application. |
+| `pnpm start` | Start the production server after building. |
+| `pnpm lint` | Run Biome checks. |
+| `pnpm format` | Format the codebase with Biome. |
+| `pnpm test` | Run Jest tests. |
+| `pnpm test:watch` | Run Jest in watch mode. |
-- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
-- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
+## Engineering standards
-You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
+- Keep visual sections modular and testable.
+- Respect reduced-motion and accessibility expectations for animated sections.
+- Keep portfolio copy and case-study content easy to update without touching low-level animation code.
+- Validate interactive components with tests when changing behavior, layout assumptions, or accessibility states.
-## Deploy on Vercel
+## Validation
-The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
+Before publishing changes:
-Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
+```bash
+pnpm lint
+pnpm test
+pnpm build
+```
+
+## License
+
+Personal portfolio project unless a repository license says otherwise.
diff --git a/app/components/About.tsx b/app/components/About.tsx
index bf87ee6..3ac9328 100644
--- a/app/components/About.tsx
+++ b/app/components/About.tsx
@@ -1,7 +1,7 @@
-"use client";
+"use client";
import { motion, type Variants, useReducedMotion } from "framer-motion";
-import profilePhoto from "@/public/edev.jpeg";
+import profilePhoto from "@/public/edev.jpg";
import { Section } from "./Section";
import { DrawLine } from "./animations/DrawLine";
import { LazyRevealImage } from "./animations/LazyRevealImage";
@@ -19,6 +19,12 @@ const STORY_DATA = [
content:
"Trabalho bem em contextos com legado, integracoes complexas e pouca margem para erro, priorizando estabilidade, leitura tecnica e evolucao sustentavel.",
},
+ {
+ label: "Production mindset",
+ title: "Do codigo ao sistema no ar",
+ content:
+ "Penso alem da feature: deploy, observabilidade, manutencao e riscos de operacao entram na decisao tecnica desde o primeiro corte.",
+ },
];
const PROFILE_POINTS = [
@@ -91,7 +97,7 @@ export default function About() {
}
>
Technical profile
@@ -158,5 +164,3 @@ export default function About() {
);
}
-
-
diff --git a/app/components/Contact.tsx b/app/components/Contact.tsx
index 2f80154..ac67d68 100644
--- a/app/components/Contact.tsx
+++ b/app/components/Contact.tsx
@@ -1,16 +1,22 @@
"use client";
import type React from "react";
-import { useState } from "react";
+import { useEffect, useState } from "react";
+import { buildWhatsAppUrl, getWhatsAppDisplayNumber } from "@/lib/whatsapp";
import { motion, type Variants, useReducedMotion } from "framer-motion";
import { Section } from "./Section";
import { DrawLine } from "./animations/DrawLine";
import MagneticButton from "./cinematic/MagneticButton";
-const WHATSAPP_NUMBER = "5547992742365";
export default function Contact() {
const shouldReduceMotion = useReducedMotion();
+ const [whatsAppDisplay, setWhatsAppDisplay] = useState("WhatsApp");
+
+ useEffect(() => {
+ setWhatsAppDisplay(getWhatsAppDisplayNumber());
+ }, []);
+
const fieldClassName =
"mt-sp-2 w-full border border-[rgba(255,255,255,.12)] bg-[rgba(255,255,255,.06)] px-sp-4 py-[14px] text-[13px] leading-6 text-white outline-none transition-[border-color,box-shadow] focus-visible:border-[var(--slash)] focus-visible:ring-2 focus-visible:ring-[rgba(204,255,0,0.34)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--ink)]";
const [formData, setFormData] = useState({
@@ -25,8 +31,7 @@ export default function Contact() {
const messageTemplate = `*NOVA SOLICITACAO DE PROJETO*\n\n*Origem:* Portfolio Profissional\n*Prioridade:* Alta\n\n---\n*CLIENTE:* ${formData.name}\n*EMAIL:* ${formData.email}\n*AREA:* ${formData.subject.toUpperCase()}\n\n*DESCRICAO:*\n"${formData.message}"\n---\n_Mensagem gerada via Evandro.dev | Garuva, SC_`;
- const encodedMessage = encodeURIComponent(messageTemplate);
- const whatsappUrl = `https://wa.me/${WHATSAPP_NUMBER}?text=${encodedMessage}`;
+ const whatsappUrl = buildWhatsAppUrl(messageTemplate);
window.open(whatsappUrl, "_blank", "noopener,noreferrer");
};
@@ -93,7 +98,7 @@ export default function Contact() {
projeto, performance ou construcao de produto com ownership real.
-
WhatsApp: +55 47 99274-2365
+
WhatsApp: {whatsAppDisplay}
E-mail: evandrofonsecajunior@gmail.com
Base: Garuva, Santa Catarina | atuacao remota
diff --git a/app/components/ContactForm.tsx b/app/components/ContactForm.tsx
index 5027462..df44114 100644
--- a/app/components/ContactForm.tsx
+++ b/app/components/ContactForm.tsx
@@ -2,6 +2,7 @@
import { useState, ChangeEvent, FormEvent, useEffect } from "react";
import { usePortfolioData } from "@/lib/usePortfolioData";
+import { buildWhatsAppUrl } from "@/lib/whatsapp";
import { motion } from "motion/react";
interface ContactFormProps {
@@ -173,15 +174,12 @@ ${formData.userName}`;
const handleEmailFocus = () => setEmailFocused(true);
const handlePhoneFocus = () => setPhoneFocused(true);
- const generateWhatsAppUrl = () => {
- const message = encodeURIComponent(
+ const generateWhatsAppUrl = () =>
+ buildWhatsAppUrl(
formType === "advanced"
? generateAdvancedMessage()
: formData.customMessage || getGreetingMessageWithUserName(),
);
- const phone = data.contact.whatsapp.replace(/\D/g, ""); // Remove caracteres não numéricos
- return `https://wa.me/${phone}?text=${message}`;
- };
const generateEmailUrl = () => {
const subject = encodeURIComponent("Proposta de Projeto - Portfólio");
diff --git a/app/components/ContactInfo.tsx b/app/components/ContactInfo.tsx
index 017fd6b..2f8913c 100644
--- a/app/components/ContactInfo.tsx
+++ b/app/components/ContactInfo.tsx
@@ -1,8 +1,10 @@
"use client";
+import { useEffect, useState } from "react";
import { motion } from "motion/react";
import { Mail, MessageCircle } from "lucide-react";
import { usePortfolioData } from "@/lib/usePortfolioData";
+import { getWhatsAppDisplayNumber } from "@/lib/whatsapp";
import MagneticButton from "./cinematic/MagneticButton";
interface ContactInfoProps {
@@ -11,6 +13,11 @@ interface ContactInfoProps {
export function ContactInfo({ onWhatsAppClick }: ContactInfoProps) {
const { data } = usePortfolioData();
+ const [whatsAppDisplay, setWhatsAppDisplay] = useState("WhatsApp");
+
+ useEffect(() => {
+ setWhatsAppDisplay(getWhatsAppDisplayNumber());
+ }, []);
if (!data) {
return null; // Ou um componente de carregamento/erro
@@ -58,7 +65,7 @@ export function ContactInfo({ onWhatsAppClick }: ContactInfoProps) {
WhatsApp
-
{data.contact.whatsapp}
+
{whatsAppDisplay}
diff --git a/app/components/Hero.reducedMotion.test.tsx b/app/components/Hero.reducedMotion.test.tsx
index e4eeb2c..5d7e4cd 100644
--- a/app/components/Hero.reducedMotion.test.tsx
+++ b/app/components/Hero.reducedMotion.test.tsx
@@ -1,9 +1,15 @@
-import { render, screen } from "@testing-library/react";
+import { render, screen, waitFor } from "@testing-library/react";
import type { ReactNode } from "react";
import Hero from "./Hero";
-let mockReducedMotion = false;
+jest.mock("next/dynamic", () => () => {
+ const DynamicComponent = ({ variant }: { variant?: string }) => (
+
+ );
+ DynamicComponent.displayName = "MockHeroScene";
+ return DynamicComponent;
+});
jest.mock("framer-motion", () => {
const React = require("react");
@@ -16,15 +22,15 @@ jest.mock("framer-motion", () => {
children,
initial,
animate,
- whileHover,
- whileTap,
+ whileHover: _whileHover,
+ whileTap: _whileTap,
+ variants: _variants,
+ transition: _transition,
...props
}: {
children?: ReactNode;
initial?: unknown;
animate?: unknown;
- whileHover?: unknown;
- whileTap?: unknown;
} & Record) => {
const dataProps = {
...(initial !== undefined
@@ -33,12 +39,6 @@ jest.mock("framer-motion", () => {
...(animate !== undefined
? { "data-animate": JSON.stringify(animate) }
: {}),
- ...(whileHover !== undefined
- ? { "data-while-hover": JSON.stringify(whileHover) }
- : {}),
- ...(whileTap !== undefined
- ? { "data-while-tap": JSON.stringify(whileTap) }
- : {}),
};
return React.createElement(tag, { ...props, ...dataProps }, children);
@@ -53,49 +53,67 @@ jest.mock("framer-motion", () => {
AnimatePresence: ({ children }: { children: React.ReactNode }) => children,
motion,
useInView: () => true,
- useReducedMotion: () => mockReducedMotion,
+ useReducedMotion: () => true,
};
});
+function mockMatchMedia(matches: boolean) {
+ Object.defineProperty(window, "matchMedia", {
+ writable: true,
+ value: jest.fn().mockImplementation((query) => ({
+ matches,
+ media: query,
+ onchange: null,
+ addListener: jest.fn(),
+ removeListener: jest.fn(),
+ addEventListener: jest.fn(),
+ removeEventListener: jest.fn(),
+ dispatchEvent: jest.fn(),
+ })),
+ });
+}
+
describe("Hero reduced motion", () => {
- afterEach(() => {
- mockReducedMotion = false;
+ beforeEach(() => {
+ mockMatchMedia(true);
+ jest.spyOn(Math, "random").mockReturnValue(0);
});
- it("removes hover/tap scale animations when reduced motion is enabled", () => {
- mockReducedMotion = true;
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+ it("keeps essential hero content visible with reduced motion enabled", async () => {
+ render( );
+
+ await waitFor(() =>
+ expect(screen.queryByTestId("hero-scene")).not.toBeInTheDocument(),
+ );
+
+ expect(screen.getByText(/Command center online/i)).toBeInTheDocument();
+ expect(
+ screen.getByRole("heading", {
+ level: 1,
+ name: /coloque seu sistema no ar/i,
+ }),
+ ).toBeInTheDocument();
+ expect(
+ screen.getByRole("button", { name: /botar meu sistema no ar/i }),
+ ).toBeInTheDocument();
+ });
+
+ it("keeps motion blocks declarative instead of requiring 3D", async () => {
const { container } = render( );
- const primaryAction = screen.getByText(/Iniciar projeto/i).closest("a");
- const secondaryAction = screen.getByText(/Ver projetos/i).closest("a");
-
- expect(primaryAction).not.toHaveAttribute("data-while-hover");
- expect(primaryAction).not.toHaveAttribute("data-while-tap");
- expect(secondaryAction).not.toHaveAttribute("data-while-hover");
- expect(secondaryAction).not.toHaveAttribute("data-while-tap");
+ await waitFor(() =>
+ expect(screen.queryByTestId("hero-scene")).not.toBeInTheDocument(),
+ );
const rootMotionBlock = container.querySelector(
"div[data-initial][data-animate]",
);
expect(rootMotionBlock).toBeInTheDocument();
- expect(rootMotionBlock?.getAttribute("data-initial")).toContain(
- '"opacity":0',
- );
- expect(rootMotionBlock?.getAttribute("data-animate")).toContain(
- '"opacity":1',
- );
- });
-
- it("keeps essential hero content visible with reduced motion enabled", () => {
- mockReducedMotion = true;
-
- render( );
-
- expect(screen.getByLabelText("evandro.dev.br")).toBeInTheDocument();
- expect(
- screen.getByText(/Available for selected builds/i),
- ).toBeInTheDocument();
- expect(screen.getByText(/Execution Brief/i)).toBeInTheDocument();
+ expect(rootMotionBlock?.getAttribute("data-initial")).toContain("hidden");
+ expect(rootMotionBlock?.getAttribute("data-animate")).toContain("visible");
});
});
diff --git a/app/components/Hero.test.tsx b/app/components/Hero.test.tsx
index 7f36b0a..f8ac736 100644
--- a/app/components/Hero.test.tsx
+++ b/app/components/Hero.test.tsx
@@ -1,8 +1,16 @@
-import { render, screen } from "@testing-library/react";
+import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import type { ReactNode } from "react";
import Hero from "./Hero";
+jest.mock("next/dynamic", () => () => {
+ const DynamicComponent = ({ variant }: { variant?: string }) => (
+
+ );
+ DynamicComponent.displayName = "MockHeroScene";
+ return DynamicComponent;
+});
+
jest.mock("framer-motion", () => {
const React = require("react");
@@ -12,6 +20,12 @@ jest.mock("framer-motion", () => {
get: (_, tag: string) => {
const Component = ({
children,
+ initial: _initial,
+ animate: _animate,
+ whileHover: _whileHover,
+ whileTap: _whileTap,
+ variants: _variants,
+ transition: _transition,
...props
}: { children?: ReactNode } & Record) =>
React.createElement(tag, props, children);
@@ -29,34 +43,84 @@ jest.mock("framer-motion", () => {
};
});
+function mockMatchMedia(matches = false) {
+ Object.defineProperty(window, "matchMedia", {
+ writable: true,
+ value: jest.fn().mockImplementation((query) => ({
+ matches,
+ media: query,
+ onchange: null,
+ addListener: jest.fn(),
+ removeListener: jest.fn(),
+ addEventListener: jest.fn(),
+ removeEventListener: jest.fn(),
+ dispatchEvent: jest.fn(),
+ })),
+ });
+}
+
describe("Hero", () => {
- it("renders the upgraded hero content and primary actions", () => {
- render( );
-
- expect(screen.getByLabelText("evandro.dev.br")).toBeInTheDocument();
- expect(
- screen.getByText(
- /Engenharia de software para produtos conectados, interfaces de alta performance e sistemas criticos/i,
- ),
- ).toBeInTheDocument();
-
- expect(screen.getByText(/Iniciar projeto/i)).toBeInTheDocument();
- expect(screen.getByText(/Ver projetos/i)).toBeInTheDocument();
- expect(screen.getByText(/Download CV/i)).toBeInTheDocument();
- expect(screen.getByText(/Execution Brief/i)).toBeInTheDocument();
+ beforeEach(() => {
+ mockMatchMedia(false);
+ jest.spyOn(Math, "random").mockReturnValue(0);
+ jest.spyOn(window, "open").mockImplementation(() => null);
});
- it("renders social links and proof content", () => {
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
+ it("renders the command center hero and primary actions", async () => {
+ const { container } = render( );
+
+ await waitFor(() =>
+ expect(container.querySelector("[data-hero-variant]")).toHaveAttribute(
+ "data-hero-variant",
+ "command-center",
+ ),
+ );
+
+ expect(
+ screen.getByRole("heading", {
+ level: 1,
+ name: /coloque seu sistema no ar/i,
+ }),
+ ).toBeInTheDocument();
+ expect(
+ screen.getByRole("button", { name: /botar meu sistema no ar/i }),
+ ).toBeInTheDocument();
+ expect(
+ screen.getByRole("link", { name: /ver casos selecionados/i }),
+ ).toHaveAttribute("href", "/cases");
+ expect(screen.getByText(/Download CV/i)).toBeInTheDocument();
+ expect(screen.getByTestId("hero-scene")).toHaveAttribute(
+ "data-variant",
+ "command",
+ );
+ });
+
+ it("keeps social links, proof content and WhatsApp CTA", async () => {
render( );
- expect(screen.getAllByLabelText("GitHub").length).toBeGreaterThan(0);
- expect(screen.getAllByLabelText("LinkedIn").length).toBeGreaterThan(0);
- expect(screen.getAllByLabelText("Email").length).toBeGreaterThan(0);
+ await waitFor(() =>
+ expect(screen.getByText(/Command center online/i)).toBeInTheDocument(),
+ );
+ expect(screen.getByLabelText("GitHub")).toBeInTheDocument();
+ expect(screen.getByLabelText("LinkedIn")).toBeInTheDocument();
+ expect(screen.getByLabelText("Email")).toBeInTheDocument();
expect(screen.getByText(/Garuva, SC \/ Brasil/i)).toBeInTheDocument();
- expect(screen.getByText(/Especialidade/i)).toBeInTheDocument();
- expect(screen.getByText(/Escopo/i)).toBeInTheDocument();
- expect(screen.getByText(/Formato/i)).toBeInTheDocument();
- expect(screen.getByText(/Scroll/i)).toBeInTheDocument();
+ expect(screen.getByText(/Operacao/i)).toBeInTheDocument();
+ expect(screen.getByText(/Clareza/i)).toBeInTheDocument();
+ expect(screen.getAllByText(/Resultado/i).length).toBeGreaterThan(0);
+
+ fireEvent.click(
+ screen.getByRole("button", { name: /botar meu sistema no ar/i }),
+ );
+ expect(window.open).toHaveBeenCalledWith(
+ expect.stringContaining("https://wa.me/"),
+ "_blank",
+ "noopener,noreferrer",
+ );
});
});
diff --git a/app/components/Hero.tsx b/app/components/Hero.tsx
index 04b2271..797e260 100644
--- a/app/components/Hero.tsx
+++ b/app/components/Hero.tsx
@@ -1,13 +1,42 @@
"use client";
+import { motion, type Variants } from "framer-motion";
import dynamic from "next/dynamic";
-import { motion, useReducedMotion, type Variants } from "framer-motion";
+import { useEffect, useState } from "react";
+import { buildWhatsAppUrl, getWhatsAppDisplayNumber } from "@/lib/whatsapp";
import MagneticButton from "./cinematic/MagneticButton";
const HeroScene = dynamic(() => import("./cinematic/HeroScene"), {
ssr: false,
});
+type HeroSceneVariant =
+ | "command"
+ | "launch"
+ | "rescue"
+ | "signal"
+ | "diagnostic"
+ | "portrait";
+
+type HeroVariant = {
+ id: string;
+ weight: number;
+ scene: HeroSceneVariant;
+ layout: "default" | "visual-first" | "split" | "report" | "portrait";
+ status: string;
+ chip: string;
+ eyebrow: string;
+ headline: string;
+ subtitle: string;
+ cta: string;
+ whatsappMessage: string;
+ sideLabel: string;
+ sideTitle: string;
+ sideText: string;
+ points: string[];
+ proof: Array<{ label: string; value: string }>;
+};
+
const SOCIAL_LINKS = [
{
href: "https://github.com/evandrodevbr",
@@ -36,50 +65,402 @@ const SOCIAL_LINKS = [
},
];
-const HERO_POINTS = [
- "Produtos conectados, integracoes complexas e operacoes criticas.",
- "Arquitetura mais clara para evoluir sem aumentar o caos tecnico.",
- "Execucao ponta a ponta, do discovery a entrega em producao.",
+const HERO_VARIANTS: HeroVariant[] = [
+ {
+ id: "command-center",
+ weight: 22,
+ scene: "command",
+ layout: "default",
+ status: "Command center online",
+ chip: "Sistemas em producao, sem improviso",
+ eyebrow:
+ "Evandro Fonseca Junior | Engenharia para produtos que precisam operar",
+ headline: "Coloque seu sistema no ar com engenharia que nao improvisa.",
+ subtitle:
+ "Se voce tem um projeto travado, um MVP para lancar ou um sistema critico precisando operar melhor, agende uma conversa tecnica e saia com o proximo passo claro para producao.",
+ cta: "Botar meu sistema no ar",
+ whatsappMessage: "Ola! Quero colocar meu sistema no ar. Podemos conversar?",
+ sideLabel: "Conversa tecnica pelo WhatsApp",
+ sideTitle: "Seu projeto precisa virar sistema em producao?",
+ sideText:
+ "Me conte objetivo, prazo e contexto. Eu respondo com uma conversa direta para destravar arquitetura, entrega e deploy.",
+ points: [
+ "Conversa tecnica para tirar o projeto do papel sem improviso.",
+ "Arquitetura, codigo e deploy conectados ao resultado do negocio.",
+ "Plano claro para colocar o sistema no ar com seguranca.",
+ ],
+ proof: [
+ {
+ label: "Operacao",
+ value: "Fluxo pensado para discovery, build, deploy e sustentacao.",
+ },
+ {
+ label: "Clareza",
+ value: "Menos ruído entre produto, engenharia e decisao tecnica.",
+ },
+ {
+ label: "Resultado",
+ value: "Base pronta para operar, evoluir e receber proximo ciclo.",
+ },
+ ],
+ },
+ {
+ id: "launch-sequence",
+ weight: 18,
+ scene: "launch",
+ layout: "visual-first",
+ status: "Launch sequence ready",
+ chip: "Discovery → build → deploy",
+ eyebrow: "MVP, produto e entrega em producao",
+ headline:
+ "Tire seu MVP do plano e coloque em producao com base tecnica real.",
+ subtitle:
+ "Transformo escopo solto em sequencia de lancamento: o que validar, o que construir primeiro e como publicar sem criar uma divida tecnica logo no inicio.",
+ cta: "Lancar meu MVP",
+ whatsappMessage:
+ "Ola! Quero lancar um MVP com uma base tecnica segura. Podemos conversar?",
+ sideLabel: "Sequencia de lancamento",
+ sideTitle: "Do primeiro corte ao deploy.",
+ sideText:
+ "A conversa define prioridade, risco e o menor caminho confiavel para colocar a primeira versao no ar.",
+ points: [
+ "Recorte de MVP sem inflar escopo.",
+ "Entrega incremental com criterio de producao.",
+ "Deploy e continuidade pensados desde o inicio.",
+ ],
+ proof: [
+ { label: "01", value: "Diagnostico do objetivo e gargalo principal." },
+ { label: "02", value: "Plano de construcao com risco visivel." },
+ { label: "03", value: "Publicacao e proximo ciclo sem perder contexto." },
+ ],
+ },
+ {
+ id: "rescue-split",
+ weight: 16,
+ scene: "rescue",
+ layout: "split",
+ status: "Rescue mode available",
+ chip: "Legado, instabilidade e projeto travado",
+ eyebrow: "Rescue tecnico para sistemas que precisam voltar a andar",
+ headline:
+ "Codigo confuso, entrega travada ou sistema instavel? Vamos organizar.",
+ subtitle:
+ "Entro no ponto onde o projeto parou: leio o fluxo real, separo sintoma de causa e transformo caos tecnico em plano executavel.",
+ cta: "Destravar meu projeto",
+ whatsappMessage:
+ "Ola! Tenho um projeto travado ou instavel e quero destravar. Podemos conversar?",
+ sideLabel: "Antes / depois tecnico",
+ sideTitle: "Do caos operacional para uma rota clara.",
+ sideText:
+ "O primeiro objetivo nao e reescrever tudo. E encontrar o menor corte seguro que devolve controle e previsibilidade.",
+ points: [
+ "Leitura rapida de fluxo, risco e acoplamento.",
+ "Priorizacao do que destrava sem reescrever tudo.",
+ "Correcoes com criterio para nao trocar um bug por outro.",
+ ],
+ proof: [
+ {
+ label: "Antes",
+ value: "Backlog confuso, bugs recorrentes e pouca previsibilidade.",
+ },
+ {
+ label: "Intervencao",
+ value: "Mapa de risco, cortes pequenos e decisao tecnica clara.",
+ },
+ { label: "Depois", value: "Entrega volta a andar com menos improviso." },
+ ],
+ },
+ {
+ id: "iot-signal-map",
+ weight: 15,
+ scene: "signal",
+ layout: "default",
+ status: "Signal map active",
+ chip: "Hardware + software + operacao",
+ eyebrow: "Produtos conectados, telemetria e integracoes criticas",
+ headline:
+ "Conecte dispositivo, backend e interface em uma operacao confiavel.",
+ subtitle:
+ "Atuo na fronteira que costuma quebrar primeiro: sinal fisico, API, painel, dados e rotina operacional funcionando como um unico produto.",
+ cta: "Conectar meu produto",
+ whatsappMessage:
+ "Ola! Quero conectar hardware, software e operacao em um produto confiavel. Podemos conversar?",
+ sideLabel: "Mapa de sinais",
+ sideTitle: "Dados, comandos e painel no mesmo fluxo.",
+ sideText:
+ "A conversa identifica fontes de dados, contratos, pontos de falha e o caminho para transformar integracao em produto.",
+ points: [
+ "Contratos claros entre dispositivo, API e interface.",
+ "Telemetria e dashboards com contexto operacional.",
+ "Base pronta para automacao, IA ou analytics.",
+ ],
+ proof: [
+ {
+ label: "Entrada",
+ value: "Sensores, dispositivos, eventos ou sistemas externos.",
+ },
+ {
+ label: "Meio",
+ value: "APIs, WebSockets, filas, banco e observabilidade.",
+ },
+ {
+ label: "Saida",
+ value: "Painel, operacao, alerta e decisao de produto.",
+ },
+ ],
+ },
+ {
+ id: "diagnostic-report",
+ weight: 15,
+ scene: "diagnostic",
+ layout: "report",
+ status: "Diagnostic report open",
+ chip: "Arquitetura antes de mais codigo",
+ eyebrow: "Diagnostico tecnico para decidir melhor",
+ headline: "Antes de escrever mais codigo, descubra o proximo passo certo.",
+ subtitle:
+ "Quando a base cresce sem clareza, mais features podem piorar o problema. Eu ajudo a mapear risco, arquitetura e prioridades antes da proxima decisao cara.",
+ cta: "Agendar diagnostico",
+ whatsappMessage:
+ "Ola! Quero um diagnostico tecnico para decidir o proximo passo do meu sistema. Podemos conversar?",
+ sideLabel: "Relatorio tecnico",
+ sideTitle: "Risco, arquitetura e rota de acao.",
+ sideText:
+ "Ideal para produto que precisa escalar, migrar, estabilizar ou parar de acumular retrabalho tecnico.",
+ points: [
+ "Mapa claro dos gargalos e dependencias.",
+ "Trade-offs traduzidos para decisao de negocio.",
+ "Plano de transicao sem promessa magica.",
+ ],
+ proof: [
+ { label: "Risco", value: "O que pode quebrar, atrasar ou custar caro." },
+ {
+ label: "Arquitetura",
+ value: "Onde simplificar, separar ou estabilizar primeiro.",
+ },
+ { label: "Acao", value: "Proximo corte de implementacao com criterio." },
+ ],
+ },
+ {
+ id: "cinematic-portrait",
+ weight: 14,
+ scene: "portrait",
+ layout: "portrait",
+ status: "Direct technical partner",
+ chip: "Conversa direta com quem implementa",
+ eyebrow: "Engenharia senior, ownership e execucao",
+ headline: "Um parceiro tecnico para transformar complexidade em entrega.",
+ subtitle:
+ "Voce nao precisa apenas de tela bonita ou codigo isolado. Precisa de alguem que entenda contexto, escolha o corte certo e acompanhe ate o sistema operar.",
+ cta: "Falar com Evandro",
+ whatsappMessage:
+ "Ola Evandro! Quero conversar sobre um projeto e entender como podemos colocar esse sistema no ar.",
+ sideLabel: "Founder-led engineering",
+ sideTitle: "Menos repasse, mais ownership.",
+ sideText:
+ "A conversa e comigo: contexto tecnico, prioridade, risco e caminho de entrega sem perder informacao entre camadas.",
+ points: [
+ "Atendimento consultivo com leitura tecnica real.",
+ "Do produto ao backend sem perder contexto.",
+ "Execucao com criterio, nao so codigo por demanda.",
+ ],
+ proof: [
+ {
+ label: "Perfil",
+ value: "Engenharia full-stack com base em sistemas e integracoes.",
+ },
+ {
+ label: "Postura",
+ value: "Clareza, autonomia e decisao tecnica pragmatica.",
+ },
+ {
+ label: "Acesso",
+ value: "WhatsApp direto para conversa tecnica inicial.",
+ },
+ ],
+ },
];
-const PROOF_ITEMS = [
- {
- label: "Quem eu ajudo",
- value:
- "Empresas que dependem de integracoes, hardware ou fluxos criticos para operar com seguranca e previsibilidade.",
- },
- {
- label: "Como entrego",
- value:
- "Traduzo complexidade tecnica em backlog claro, arquitetura legivel e decisao mais rapida para o time.",
- },
- {
- label: "Por que conversar",
- value:
- "Voce ganha um parceiro tecnico capaz de conectar produto, backend, interface e operacao sem perder contexto.",
- },
-];
+const LAYOUT_CLASSES: Record = {
+ default:
+ "grid items-start gap-sp-8 lg:grid-cols-[minmax(0,1.1fr)_minmax(340px,0.9fr)] lg:gap-sp-10",
+ "visual-first":
+ "grid items-start gap-sp-8 lg:grid-cols-[minmax(340px,0.9fr)_minmax(0,1.1fr)] lg:gap-sp-10",
+ split: "grid items-stretch gap-sp-8 lg:grid-cols-2 lg:gap-sp-10",
+ report:
+ "grid items-start gap-sp-8 lg:grid-cols-[minmax(360px,0.85fr)_minmax(0,1.15fr)] lg:gap-sp-10",
+ portrait:
+ "grid items-center gap-sp-8 lg:grid-cols-[minmax(0,1fr)_minmax(320px,0.72fr)] lg:gap-sp-10",
+};
+
+function pickWeightedHeroVariant() {
+ const total = HERO_VARIANTS.reduce((sum, variant) => sum + variant.weight, 0);
+ let ticket = Math.random() * total;
+
+ for (const variant of HERO_VARIANTS) {
+ ticket -= variant.weight;
+ if (ticket <= 0) return variant;
+ }
+
+ return HERO_VARIANTS[0];
+}
+
+function getGreeting(message: string) {
+ const hour = new Date().getHours();
+ if (hour >= 8 && hour < 12) return `Bom dia! ${message}`;
+ if (hour >= 13 && hour < 18) return `Boa tarde! ${message}`;
+ return message;
+}
+
+function SideVisual({ variant }: { variant: HeroVariant }) {
+ if (variant.scene === "launch") {
+ return (
+
+ {variant.proof.map((item, index) => (
+
+
+ 0{index + 1}
+
+
+
+ {item.label}
+
+
+ {item.value}
+
+
+
+ ))}
+
+ );
+ }
+
+ if (variant.scene === "rescue") {
+ return (
+
+
+
+ Antes
+
+
+ Bugs recorrentes, escopo nebuloso e medo de mexer.
+
+
+
+
+ Depois
+
+
+ Rota clara, cortes menores e entrega voltando a andar.
+
+
+
+ );
+ }
+
+ if (variant.scene === "signal") {
+ return (
+
+
+
+ {[28, 150, 284, 400].map((x, index) => (
+
+ ))}
+
+
+ );
+ }
+
+ if (variant.scene === "diagnostic") {
+ return (
+
+
+ Risk report
+ Actionable
+
+
+ {variant.proof.map((item) => (
+
+
+ {item.label}
+ mapped
+
+
+
+ ))}
+
+
+ );
+ }
+
+ if (variant.scene === "portrait") {
+ return (
+
+
+ EFJ
+
+
+ Engenharia com contato direto
+
+
+ );
+ }
+
+ return (
+
+ {["deploy pipeline", "api health", "production ready"].map((item) => (
+
+ {item}
+ ok
+
+ ))}
+
+ );
+}
export default function Hero() {
- const shouldReduceMotion = useReducedMotion();
+ const [variant, setVariant] = useState(HERO_VARIANTS[0]);
+ const [shouldReduceMotion, setShouldReduceMotion] = useState(false);
+ const [whatsAppDisplay, setWhatsAppDisplay] = useState("WhatsApp");
- const hour = new Date().getHours();
- const greeting =
- hour >= 8 && hour < 12
- ? "Ola! Vi seu portfolio. Podemos conversar?"
- : hour >= 13 && hour < 18
- ? "Boa tarde! Vi seu portfolio. Podemos conversar?"
- : "Ola! Vi seu portfolio. Podemos conversar quando estiver disponivel?";
+ useEffect(() => {
+ setVariant(pickWeightedHeroVariant());
+ setShouldReduceMotion(
+ window.matchMedia("(prefers-reduced-motion: reduce)").matches,
+ );
+ setWhatsAppDisplay(getWhatsAppDisplayNumber());
+ }, []);
+
+ const handleWhatsAppClick = () => {
+ window.open(
+ buildWhatsAppUrl(getGreeting(variant.whatsappMessage)),
+ "_blank",
+ "noopener,noreferrer",
+ );
+ };
- // Cinematic stagger variants
const heroContainer: Variants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
- transition: {
- staggerChildren: 0.1,
- delayChildren: 0.3,
- },
+ transition: { staggerChildren: 0.1, delayChildren: 0.3 },
},
};
@@ -93,10 +474,7 @@ export default function Hero() {
opacity: 1,
y: 0,
filter: "blur(0px)",
- transition: {
- duration: 1,
- ease: easeOut,
- },
+ transition: { duration: 1, ease: easeOut },
},
};
@@ -108,26 +486,29 @@ export default function Hero() {
opacity: 1,
y: 0,
filter: "blur(0px)",
- transition: {
- duration: 1.2,
- ease: easeOut,
- },
+ transition: { duration: 1.2, ease: easeOut },
},
};
+ const contentOrder =
+ variant.layout === "visual-first" || variant.layout === "report"
+ ? "lg:order-2"
+ : "";
+ const panelOrder =
+ variant.layout === "visual-first" || variant.layout === "report"
+ ? "lg:order-1"
+ : "";
+
return (
- {/* 3D Scene Background */}
- {!shouldReduceMotion && }
+ {!shouldReduceMotion && }
- {/* Cinematic overlays */}
-
- {/* Scanlines effect */}
-
- {/* Vignette */}
@@ -144,10 +523,9 @@ export default function Hero() {
initial="hidden"
animate="visible"
variants={heroContainer}
- className="grid items-start gap-sp-8 lg:grid-cols-[minmax(0,1.1fr)_minmax(340px,0.9fr)] lg:gap-sp-10"
+ className={LAYOUT_CLASSES[variant.layout]}
>
-
- {/* Status badge with glow */}
+
- Available for selected builds
+ {variant.status}
- Produtos conectados, integracoes criticas e entrega ponta a ponta
+ {variant.chip}
- {/* Eyebrow */}
- Evandro Fonseca Junior | Engenheiro de software full-stack
+ {variant.eyebrow}
- {/* Main heading with cinematic reveal */}
- Engenharia de software para sistemas que nao podem falhar.
+ {variant.headline}
- {/* Subtitle */}
- Ajudo empresas com produtos conectados, integracoes complexas e
- operacoes criticas a transformar arquitetura confusa em software
- estavel, mais rapido de evoluir e muito mais facil de operar.
+ {variant.subtitle}
- {/* Key points with staggered reveal */}
- {HERO_POINTS.map((point, i) => (
+ {variant.points.map((point, i) => (
- {/* CTAs with magnetic effect */}
- Agendar conversa tecnica
+ {variant.cta}
- {/* Footer info with reveal */}
- {/* Aside card with cinematic entrance */}
- {/* Top glow line */}
+
+
- Why this positioning works
+ {variant.sideLabel}
- Menos atrito entre produto, engenharia e operacao.
+ {variant.sideTitle}
- Entro onde a complexidade cresce e ajudo a devolver clareza,
- ritmo de entrega e confiabilidade para o sistema e para o time.
+ {variant.sideText}
+
+ Agendar no WhatsApp: {whatsAppDisplay}
+
- {PROOF_ITEMS.map((item, index) => (
+ {variant.proof.map((item, index) => (
- {/* Scroll indicator */}
(0);
@@ -29,7 +22,7 @@ export default function CustomCursor() {
if (!isVisible) setIsVisible(true);
});
},
- [cursorX, cursorY, isVisible]
+ [cursorX, cursorY, isVisible],
);
useEffect(() => {
@@ -57,7 +50,7 @@ export default function CustomCursor() {
function attachHoverListeners() {
const hoverables = document.querySelectorAll(
- 'a, button, [role="button"], input, textarea, select, [data-cursor]'
+ 'a, button, [role="button"], input, textarea, select, [data-cursor]',
);
for (const el of hoverables) {
el.addEventListener("mouseenter", handleElementEnter as EventListener);
@@ -89,7 +82,10 @@ export default function CustomCursor() {
}, [handleMouseMove]);
// Don't render on touch devices
- if (typeof window !== "undefined" && !window.matchMedia("(pointer: fine)").matches) {
+ if (
+ typeof window !== "undefined" &&
+ !window.matchMedia("(pointer: fine)").matches
+ ) {
return null;
}
@@ -105,8 +101,8 @@ export default function CustomCursor() {
{hoverText && (
(null);
const mouseRef = useRef({ x: 0, y: 0 });
@@ -32,10 +40,13 @@ function ParticleField({ count = 2000 }: { count?: number }) {
return s;
}, [count]);
- const handlePointerMove = useCallback((e: { clientX: number; clientY: number }) => {
- mouseRef.current.x = (e.clientX / window.innerWidth) * 2 - 1;
- mouseRef.current.y = -(e.clientY / window.innerHeight) * 2 + 1;
- }, []);
+ const handlePointerMove = useCallback(
+ (e: { clientX: number; clientY: number }) => {
+ mouseRef.current.x = (e.clientX / window.innerWidth) * 2 - 1;
+ mouseRef.current.y = -(e.clientY / window.innerHeight) * 2 + 1;
+ },
+ [],
+ );
useFrame((state) => {
if (!mesh.current) return;
@@ -107,22 +118,61 @@ function ParticleField({ count = 2000 }: { count?: number }) {
);
}
-function FloatingGeometry() {
+function FloatingGeometry({ variant }: { variant: HeroSceneVariant }) {
const meshRef = useRef(null);
const mesh2Ref = useRef(null);
const mesh3Ref = useRef(null);
+ const layout = {
+ command: {
+ a: [4, 1.5, -3] as [number, number, number],
+ b: [-5, -2, -4] as [number, number, number],
+ c: [2, -3, -5] as [number, number, number],
+ scale: [1.2, 0.8, 1.5] as [number, number, number],
+ },
+ launch: {
+ a: [3.8, 2.1, -3] as [number, number, number],
+ b: [0, -1.4, -4] as [number, number, number],
+ c: [-3.8, -2.6, -5] as [number, number, number],
+ scale: [0.9, 0.9, 1.8] as [number, number, number],
+ },
+ rescue: {
+ a: [-3.6, 1.2, -3] as [number, number, number],
+ b: [3.6, 1.2, -4] as [number, number, number],
+ c: [0, -2.8, -5] as [number, number, number],
+ scale: [1, 1, 1.4] as [number, number, number],
+ },
+ signal: {
+ a: [-4.2, -1, -3] as [number, number, number],
+ b: [0.2, 1.6, -4] as [number, number, number],
+ c: [4.2, -0.6, -5] as [number, number, number],
+ scale: [0.7, 0.7, 1.2] as [number, number, number],
+ },
+ diagnostic: {
+ a: [4.6, 0.6, -3] as [number, number, number],
+ b: [-3.5, 1.8, -4] as [number, number, number],
+ c: [-1.2, -2.8, -5] as [number, number, number],
+ scale: [1.4, 0.7, 1.1] as [number, number, number],
+ },
+ portrait: {
+ a: [3.2, 0.4, -3] as [number, number, number],
+ b: [4.8, 2.1, -4] as [number, number, number],
+ c: [-3.6, -2.4, -5] as [number, number, number],
+ scale: [1.8, 0.5, 1.1] as [number, number, number],
+ },
+ }[variant];
+
useFrame((state) => {
const t = state.clock.elapsedTime;
if (meshRef.current) {
meshRef.current.rotation.x = t * 0.15;
meshRef.current.rotation.y = t * 0.1;
- meshRef.current.position.y = Math.sin(t * 0.4) * 0.3;
+ meshRef.current.position.y = layout.a[1] + Math.sin(t * 0.4) * 0.3;
}
if (mesh2Ref.current) {
mesh2Ref.current.rotation.x = t * 0.1;
mesh2Ref.current.rotation.z = t * 0.12;
- mesh2Ref.current.position.y = Math.cos(t * 0.3) * 0.5;
+ mesh2Ref.current.position.y = layout.b[1] + Math.cos(t * 0.3) * 0.5;
}
if (mesh3Ref.current) {
mesh3Ref.current.rotation.y = t * 0.08;
@@ -133,13 +183,19 @@ function FloatingGeometry() {
return (
<>
-
-
+
+ {variant === "diagnostic" ? (
+
+ ) : variant === "portrait" ? (
+
+ ) : (
+
+ )}
@@ -147,8 +203,14 @@ function FloatingGeometry() {
-
-
+
+ {variant === "launch" ? (
+
+ ) : variant === "signal" ? (
+
+ ) : (
+
+ )}
-
-
+
+ {variant === "rescue" ? (
+
+ ) : variant === "signal" ? (
+
+ ) : (
+
+ )}
-
+
-
+
diff --git a/app/globals.css b/app/globals.css
index cfd122e..f3c01c6 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -62,17 +62,39 @@
padding: 0;
}
+html,
+body {
+ width: 100%;
+ max-width: 100%;
+ overflow-x: hidden;
+ overscroll-behavior-x: none;
+}
+
html {
scroll-behavior: smooth;
}
body {
+ position: relative;
background: var(--paper);
color: var(--ink);
font-family: var(--font-mono);
font-size: 14px;
line-height: 1.68;
- overflow-x: hidden;
+}
+
+img,
+video,
+canvas,
+svg {
+ max-width: 100%;
+}
+
+@supports (overflow: clip) {
+ html,
+ body {
+ overflow-x: clip;
+ }
}
a {
diff --git a/app/opengraph-image.tsx b/app/opengraph-image.tsx
index c53d052..5bf4c30 100644
--- a/app/opengraph-image.tsx
+++ b/app/opengraph-image.tsx
@@ -1,6 +1,5 @@
import { ImageResponse } from "next/og";
-export const runtime = "edge";
export const alt = "Evandro Fonseca Junior - Engenheiro de Software";
export const size = {
width: 1200,
diff --git a/docs/superpowers/plans/2026-07-08-random-hero-variations.md b/docs/superpowers/plans/2026-07-08-random-hero-variations.md
new file mode 100644
index 0000000..74ab219
--- /dev/null
+++ b/docs/superpowers/plans/2026-07-08-random-hero-variations.md
@@ -0,0 +1,61 @@
+# Random Hero Variations Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** Build six weighted, randomly selected Hero Section layouts with matching 3D scene modes.
+
+**Architecture:** Add data-driven hero variant configuration in `Hero.tsx`, choose a variant once on client mount, and render layout-specific panel/accent components from that config. Update `HeroScene.tsx` to accept a scene variant prop and switch geometry composition without adding dependencies.
+
+**Tech Stack:** Next.js, React 19, TypeScript, Framer Motion, @react-three/fiber, @react-three/drei, Three.js.
+
+---
+
+### Task 1: Add variant data and weighted picker
+
+**Files:**
+- Modify: `app/components/Hero.tsx`
+
+- [ ] Define `HeroVariantId`, `HeroSceneVariant`, and `HeroVariant` types.
+- [ ] Add six approved variant objects with copy, points, proof items, side panel mode, layout mode, CTA text, and weights.
+- [ ] Add `pickWeightedHeroVariant()` using `Math.random()` and relative weights.
+- [ ] Keep `HERO_VARIANTS[0]` as deterministic SSR/default fallback.
+
+### Task 2: Render six hero layouts from shared primitives
+
+**Files:**
+- Modify: `app/components/Hero.tsx`
+
+- [ ] Replace fixed hero text with selected variant data.
+- [ ] Add layout-specific class maps for Command Center, Launch Sequence, Rescue Split, IoT Signal Map, Diagnostic Report, and Cinematic Portrait.
+- [ ] Add side panel renderer that draws distinct visual panels for each mode using existing CSS/Tailwind utilities.
+- [ ] Keep primary WhatsApp CTA and secondary cases/CV actions.
+
+### Task 3: Parameterize the 3D scene
+
+**Files:**
+- Modify: `app/components/cinematic/HeroScene.tsx`
+
+- [ ] Export/accept a `HeroSceneVariant`-compatible prop locally as string union.
+- [ ] Pass the selected scene mode from `Hero.tsx` into `HeroScene`.
+- [ ] Change floating geometry positions/geometries per scene mode.
+- [ ] Keep reduced motion behavior unchanged: no `HeroScene` render when reduced motion is enabled.
+
+### Task 4: Update tests
+
+**Files:**
+- Modify: `app/components/Hero.test.tsx`
+- Modify: `app/components/Hero.reducedMotion.test.tsx`
+
+- [ ] Update assertions to current commercial CTA/copy.
+- [ ] Assert at least one approved hero layout renders.
+- [ ] Assert CTA remains a button and cases/CV remain available.
+- [ ] Assert reduced-motion content still renders without animation-specific failures.
+
+### Task 5: Verify
+
+**Commands:**
+- `pnpm exec tsc --noEmit --pretty false`
+- `pnpm test -- Hero.test.tsx Hero.reducedMotion.test.tsx --runInBand`
+- `pnpm build`
+
+**Expected:** all commands exit 0.
diff --git a/docs/superpowers/specs/2026-07-08-random-hero-variations-design.md b/docs/superpowers/specs/2026-07-08-random-hero-variations-design.md
new file mode 100644
index 0000000..ef85343
--- /dev/null
+++ b/docs/superpowers/specs/2026-07-08-random-hero-variations-design.md
@@ -0,0 +1,37 @@
+# Random Hero Variations Design
+
+## Goal
+
+Create six structurally different Hero Section variations for the portfolio home page. Each visit should pick one variation randomly using weighted probability, while preserving the existing visual identity: dark cinematic background, slash green accent, glass panels, mono labels, strong display typography, technical lines, and WhatsApp conversion CTA.
+
+## Approved hero variants
+
+1. **Command Center** — Main/default hero. Two-column mission-control layout with production status, deploy/operation language, and strong CTA.
+2. **Launch Sequence** — Timeline/checklist layout showing discovery → build → deploy, focused on launching MVPs and putting systems in production.
+3. **Before / After Rescue** — Split layout comparing technical chaos vs organized system, focused on legacy, instability, and rescue projects.
+4. **IoT Signal Map** — Signal/network layout with nodes and telemetry language, focused on hardware + software, APIs, dashboards, and connected products.
+5. **Diagnostic Report** — Report/audit layout with risk, architecture, and next-step panels, focused on technical diagnosis before more code.
+6. **Cinematic Portrait** — More personal consultant-led layout with trust, direct conversation, and premium technical partner positioning.
+
+## Weighted distribution
+
+- Command Center: 22
+- Launch Sequence: 18
+- Before / After Rescue: 16
+- IoT Signal Map: 15
+- Diagnostic Report: 15
+- Cinematic Portrait: 14
+
+Weights are relative. Command Center appears most often because it is the clearest commercial positioning.
+
+## Implementation approach
+
+Keep the implementation lazy and maintainable: one data array defines copy, layout, side panel, points, CTA, and scene mode. `Hero.tsx` renders the same primitives with layout-specific branches instead of six separate full components. `HeroScene.tsx` accepts a `variant` prop and changes the 3D object composition per selected hero.
+
+## Constraints
+
+- Do not expose the WhatsApp number as a complete literal.
+- Do not add dependencies.
+- Keep accessibility basics: real buttons/links, visible text, keyboard focus.
+- Avoid horizontal scroll.
+- Reduced motion must continue to hide the 3D scene.
diff --git a/lib/site-content.ts b/lib/site-content.ts
index fbf90fa..043d8b4 100644
--- a/lib/site-content.ts
+++ b/lib/site-content.ts
@@ -61,8 +61,7 @@ export const servicePages: ServicePageContent[] = [
],
stack: ["Next.js", "TypeScript", "Node.js", "PostgreSQL", "APIs REST"],
ctaLabel: "Agendar conversa sobre engenharia",
- ctaHref:
- "https://wa.me/5547992742365?text=Quero%20conversar%20sobre%20engenharia%20de%20software.",
+ ctaHref: "/#contact",
relatedCaseIds: ["nutriscan", "reddit-explorer", "sc-plus"],
},
{
@@ -96,7 +95,7 @@ export const servicePages: ServicePageContent[] = [
],
stack: ["Next.js", "React", "TypeScript", "Tailwind CSS", "SEO tecnico"],
ctaLabel: "Solicitar consultoria Next.js",
- ctaHref: "https://wa.me/5547992742365?text=Quero%20consultoria%20em%20Next.js.",
+ ctaHref: "/#contact",
relatedCaseIds: ["nutriscan", "twins-lab", "sc-plus"],
},
{
@@ -136,8 +135,7 @@ export const servicePages: ServicePageContent[] = [
"System integration",
],
ctaLabel: "Conversar sobre Tauri e Rust",
- ctaHref:
- "https://wa.me/5547992742365?text=Quero%20conversar%20sobre%20Tauri%20e%20Rust.",
+ ctaHref: "/#contact",
relatedCaseIds: ["gcc-installer"],
},
{
@@ -170,8 +168,7 @@ export const servicePages: ServicePageContent[] = [
],
stack: ["IoT", "WebSockets", "APIs", "Dashboards", "Integracao de sistemas"],
ctaLabel: "Falar sobre integracao e IoT",
- ctaHref:
- "https://wa.me/5547992742365?text=Quero%20falar%20sobre%20integracao%20hardware%20%2B%20software%20e%20IoT.",
+ ctaHref: "/#contact",
relatedCaseIds: ["twins-lab"],
},
{
@@ -211,8 +208,7 @@ export const servicePages: ServicePageContent[] = [
"Sistemas criticos",
],
ctaLabel: "Solicitar diagnostico arquitetural",
- ctaHref:
- "https://wa.me/5547992742365?text=Quero%20um%20diagnostico%20de%20arquitetura%20de%20software.",
+ ctaHref: "/#contact",
relatedCaseIds: ["nutriscan", "twins-lab", "reddit-explorer"],
},
];
diff --git a/lib/whatsapp.ts b/lib/whatsapp.ts
new file mode 100644
index 0000000..7dc3ce6
--- /dev/null
+++ b/lib/whatsapp.ts
@@ -0,0 +1,17 @@
+const COUNTRY = ["5", "5"];
+const AREA = ["4", "7"];
+const NINE = ["9"];
+const FIRST = ["9", "2", "7", "4"];
+const LAST = ["2", "3", "6", "5"];
+
+export function getWhatsAppNumber() {
+ return [...COUNTRY, ...AREA, ...NINE, ...FIRST, ...LAST].join("");
+}
+
+export function getWhatsAppDisplayNumber() {
+ return `+${COUNTRY.join("")} ${AREA.join("")} ${NINE.join("")}${FIRST.join("")}-${LAST.join("")}`;
+}
+
+export function buildWhatsAppUrl(message: string) {
+ return `https://wa.me/${getWhatsAppNumber()}?text=${encodeURIComponent(message)}`;
+}
diff --git a/next.config.ts b/next.config.ts
index be63155..e54bcad 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -9,11 +9,11 @@ const nextConfig: NextConfig = {
minimumCacheTTL: 60,
},
- // Otimizações de performance
- experimental: {
- scrollRestoration: true,
+ turbopack: {
+ root: process.cwd(),
},
+
// Headers de cache e segurança
async headers(): Promise<
Array<{ source: string; headers: Array<{ key: string; value: string }> }>
@@ -59,15 +59,6 @@ const nextConfig: NextConfig = {
},
],
},
- {
- source: "/_next/image(.*)",
- headers: [
- {
- key: "Cache-Control",
- value: "public, max-age=31536000, immutable",
- },
- ],
- },
{
source: "/fonts/(.*)",
headers: [
diff --git a/package.json b/package.json
index 5cb4a75..e6a0666 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,7 @@
"@gsap/react": "^2.1.2",
"@react-three/drei": "^10.7.7",
"@react-three/fiber": "^9.5.0",
- "@types/three": "^0.183.1",
+ "@types/three": "0.182.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cobe": "^0.6.4",
@@ -30,7 +30,7 @@
"react-dom": "19.1.0",
"tailwind-merge": "^3.3.1",
"tailwindcss-animate": "^1.0.7",
- "three": "^0.183.2"
+ "three": "0.182.0"
},
"devDependencies": {
"@biomejs/biome": "2.2.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1d2ed1c..2d449ef 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -5,13 +5,32 @@ settings:
excludeLinksFromLockfile: false
overrides:
+ '@babel/core@<=7.29.0': '>=7.29.6'
+ brace-expansion@<1.1.13: '>=1.1.13'
+ brace-expansion@>=2.0.0 <2.0.3: '>=2.0.3'
+ handlebars@>=4.0.0 <4.7.9: '>=4.7.9'
+ handlebars@>=4.0.0 <=4.7.8: '>=4.7.9'
+ handlebars@>=4.6.0 <=4.7.8: '>=4.7.9'
+ js-yaml@<=4.1.1: '>=4.2.0'
next@>=10.0.0 <15.5.10: '>=15.5.10'
next@>=15.5.1-canary.0 <15.5.10: '>=15.5.10'
+ next@>=16.0.0 <16.2.5: '>=16.2.5'
+ next@>=16.0.0 <16.2.6: '>=16.2.6'
+ next@>=16.0.0-beta.0 <16.1.7: '>=16.1.7'
+ next@>=16.0.0-beta.0 <16.2.3: '>=16.2.3'
+ next@>=16.0.1 <16.1.7: '>=16.1.7'
+ picomatch@<2.3.2: '>=2.3.2'
+ picomatch@>=4.0.0 <4.0.4: '>=4.0.4'
+ postcss@<8.5.10: '>=8.5.10'
tar@<7.5.7: '>=7.5.7'
tar@<7.5.8: '>=7.5.8'
+ tar@<=7.5.10: '>=7.5.11'
+ tar@<=7.5.15: '>=7.5.16'
tar@<=7.5.2: '>=7.5.3'
tar@<=7.5.3: '>=7.5.4'
tar@<=7.5.9: '>=7.5.10'
+ ws@>=8.0.0 <8.20.1: '>=8.20.1'
+ ws@>=8.0.0 <8.21.0: '>=8.21.0'
importers:
@@ -22,13 +41,13 @@ importers:
version: 2.1.2(gsap@3.13.0)(react@19.1.0)
'@react-three/drei':
specifier: ^10.7.7
- version: 10.7.7(@react-three/fiber@9.5.0(@types/react@19.1.12)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.183.2))(@types/react@19.1.12)(@types/three@0.183.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.183.2)
+ version: 10.7.7(@react-three/fiber@9.5.0(@types/react@19.1.12)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.182.0))(@types/react@19.1.12)(@types/three@0.182.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.182.0)
'@react-three/fiber':
specifier: ^9.5.0
- version: 9.5.0(@types/react@19.1.12)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.183.2)
+ version: 9.5.0(@types/react@19.1.12)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.182.0)
'@types/three':
- specifier: ^0.183.1
- version: 0.183.1
+ specifier: 0.182.0
+ version: 0.182.0
class-variance-authority:
specifier: ^0.7.1
version: 0.7.1
@@ -54,8 +73,8 @@ importers:
specifier: ^12.23.12
version: 12.23.12(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
next:
- specifier: '>=15.5.10'
- version: 16.1.6(@babel/core@7.29.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ specifier: '>=16.1.7'
+ version: 16.2.9(@babel/core@8.0.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
ogl:
specifier: ^1.0.11
version: 1.0.11
@@ -72,8 +91,8 @@ importers:
specifier: ^1.0.7
version: 1.0.7(tailwindcss@4.1.12)
three:
- specifier: ^0.183.2
- version: 0.183.2
+ specifier: 0.182.0
+ version: 0.182.0
devDependencies:
'@biomejs/biome':
specifier: 2.2.0
@@ -125,7 +144,7 @@ importers:
version: 4.1.12
ts-jest:
specifier: ^29.4.6
- version: 29.4.6(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(jest-util@30.3.0)(jest@30.3.0(@types/node@20.19.11)(ts-node@10.9.2(@types/node@20.19.11)(typescript@5.9.2)))(typescript@5.9.2)
+ version: 29.4.6(@babel/core@8.0.1)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@8.0.1))(jest-util@30.3.0)(jest@30.3.0(@types/node@20.19.11)(ts-node@10.9.2(@types/node@20.19.11)(typescript@5.9.2)))(typescript@5.9.2)
ts-node:
specifier: ^10.9.2
version: 10.9.2(@types/node@20.19.11)(typescript@5.9.2)
@@ -152,35 +171,33 @@ packages:
resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
engines: {node: '>=6.9.0'}
- '@babel/compat-data@7.29.0':
- resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==}
- engines: {node: '>=6.9.0'}
+ '@babel/code-frame@8.0.0':
+ resolution: {integrity: sha512-dYYg153EyN2Ekbqw2zAsbd6/JR+9N2SEoC7YV2GyyqMM7x9bLDTjBD6XBhSMLH0wtIVyJj03jWNriQhaN+eoCw==}
+ engines: {node: ^22.18.0 || >=24.11.0}
- '@babel/core@7.29.0':
- resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==}
- engines: {node: '>=6.9.0'}
+ '@babel/compat-data@8.0.0':
+ resolution: {integrity: sha512-DOjnob/cXOUgDOozCDeq/aK2p5y8dUIVdf6tNhEV1HQRd6I8aQ4f4fbtHRVEvb6lP3BGomrKHiS8ICAASSVQSw==}
+ engines: {node: ^22.18.0 || >=24.11.0}
+
+ '@babel/core@8.0.1':
+ resolution: {integrity: sha512-5FgxM4dLQpMJHSiVATk8foW263dVHQHBVpXYiimNECVWG01f4nFyEbQixeT6Mwvg7TayREJ2gpKl3o2RoMdnqw==}
+ engines: {node: ^22.18.0 || >=24.11.0}
'@babel/generator@7.29.1':
resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==}
engines: {node: '>=6.9.0'}
- '@babel/helper-compilation-targets@7.28.6':
- resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==}
- engines: {node: '>=6.9.0'}
+ '@babel/generator@8.0.0':
+ resolution: {integrity: sha512-NT9NrVwJsbSV6Y2FSstWa71EETOnzrjkL5/wX3D2mYHtKM+qvqB1DvR4D0Setb/gDBsHzRICifwEWMO8CnTF6g==}
+ engines: {node: ^22.18.0 || >=24.11.0}
- '@babel/helper-globals@7.28.0':
- resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
- engines: {node: '>=6.9.0'}
+ '@babel/helper-compilation-targets@8.0.0':
+ resolution: {integrity: sha512-JwculLABZvyPvyLBpwU/E/IbH2uM3mnxNtIJpxnIfb24y1PrdVxK5Dqjle4DpgqpGRnwgC7G8IkzPdSXZrO1Ew==}
+ engines: {node: ^22.18.0 || >=24.11.0}
- '@babel/helper-module-imports@7.28.6':
- resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-module-transforms@7.28.6':
- resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0
+ '@babel/helper-globals@8.0.0':
+ resolution: {integrity: sha512-lLozHOM6sWWlxNo8CYqHy4MBZeTvHXNgVPBfPOGsjPKUzHC2Az9QwB6gxdQmpwHl6GlQtbGgS+lj5887guDiLw==}
+ engines: {node: ^22.18.0 || >=24.11.0}
'@babel/helper-plugin-utils@7.28.6':
resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==}
@@ -190,130 +207,147 @@ packages:
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
engines: {node: '>=6.9.0'}
+ '@babel/helper-string-parser@8.0.0':
+ resolution: {integrity: sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==}
+ engines: {node: ^22.18.0 || >=24.11.0}
+
'@babel/helper-validator-identifier@7.28.5':
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
engines: {node: '>=6.9.0'}
- '@babel/helper-validator-option@7.27.1':
- resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
- engines: {node: '>=6.9.0'}
+ '@babel/helper-validator-identifier@8.0.2':
+ resolution: {integrity: sha512-9Fr9QeyCAyi1BR1jKZ6uYQ24EIhQUx5ReHfQU7drOE+TPOb+w11/dsqLkMOT2U29OdCT71XajrOT8xDc1C7orA==}
+ engines: {node: ^22.18.0 || >=24.11.0}
- '@babel/helpers@7.28.6':
- resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==}
- engines: {node: '>=6.9.0'}
+ '@babel/helper-validator-option@8.0.0':
+ resolution: {integrity: sha512-U4Dybxh4WESWHt5XhBeExi4DrY0/DNK1aHpQbsrQXCUbFHuMweT0TpLEWKvaraV2Y6fS+ZXunsZ8zIuZIgvF2Q==}
+ engines: {node: ^22.18.0 || >=24.11.0}
+
+ '@babel/helpers@8.0.0':
+ resolution: {integrity: sha512-wfbi91pM3py96oIiJEz7qIpyXDytgr9zQC1HEWwlGNVRAEmItuU/0a41ZUKu1sJGyhhOIpc4t5vk4PYzt8wpsg==}
+ engines: {node: ^22.18.0 || >=24.11.0}
'@babel/parser@7.29.0':
resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==}
engines: {node: '>=6.0.0'}
hasBin: true
+ '@babel/parser@8.0.0':
+ resolution: {integrity: sha512-aLxAE+imI9bCcyaPrUDjBv3uSkWieifjLe0kuFOZF0zli0L6GCsTmsePnTr55adbIAgYz2zhN1vnFimCBUYcRQ==}
+ engines: {node: ^22.18.0 || >=24.11.0}
+ hasBin: true
+
'@babel/plugin-syntax-async-generators@7.8.4':
resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==}
peerDependencies:
- '@babel/core': ^7.0.0-0
+ '@babel/core': '>=7.29.6'
'@babel/plugin-syntax-bigint@7.8.3':
resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==}
peerDependencies:
- '@babel/core': ^7.0.0-0
+ '@babel/core': '>=7.29.6'
'@babel/plugin-syntax-class-properties@7.12.13':
resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==}
peerDependencies:
- '@babel/core': ^7.0.0-0
+ '@babel/core': '>=7.29.6'
'@babel/plugin-syntax-class-static-block@7.14.5':
resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==}
engines: {node: '>=6.9.0'}
peerDependencies:
- '@babel/core': ^7.0.0-0
+ '@babel/core': '>=7.29.6'
'@babel/plugin-syntax-import-attributes@7.28.6':
resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==}
engines: {node: '>=6.9.0'}
peerDependencies:
- '@babel/core': ^7.0.0-0
+ '@babel/core': '>=7.29.6'
'@babel/plugin-syntax-import-meta@7.10.4':
resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==}
peerDependencies:
- '@babel/core': ^7.0.0-0
+ '@babel/core': '>=7.29.6'
'@babel/plugin-syntax-json-strings@7.8.3':
resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==}
peerDependencies:
- '@babel/core': ^7.0.0-0
+ '@babel/core': '>=7.29.6'
'@babel/plugin-syntax-jsx@7.28.6':
resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==}
engines: {node: '>=6.9.0'}
peerDependencies:
- '@babel/core': ^7.0.0-0
+ '@babel/core': '>=7.29.6'
'@babel/plugin-syntax-logical-assignment-operators@7.10.4':
resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==}
peerDependencies:
- '@babel/core': ^7.0.0-0
+ '@babel/core': '>=7.29.6'
'@babel/plugin-syntax-nullish-coalescing-operator@7.8.3':
resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==}
peerDependencies:
- '@babel/core': ^7.0.0-0
+ '@babel/core': '>=7.29.6'
'@babel/plugin-syntax-numeric-separator@7.10.4':
resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==}
peerDependencies:
- '@babel/core': ^7.0.0-0
+ '@babel/core': '>=7.29.6'
'@babel/plugin-syntax-object-rest-spread@7.8.3':
resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}
peerDependencies:
- '@babel/core': ^7.0.0-0
+ '@babel/core': '>=7.29.6'
'@babel/plugin-syntax-optional-catch-binding@7.8.3':
resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==}
peerDependencies:
- '@babel/core': ^7.0.0-0
+ '@babel/core': '>=7.29.6'
'@babel/plugin-syntax-optional-chaining@7.8.3':
resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==}
peerDependencies:
- '@babel/core': ^7.0.0-0
+ '@babel/core': '>=7.29.6'
'@babel/plugin-syntax-private-property-in-object@7.14.5':
resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==}
engines: {node: '>=6.9.0'}
peerDependencies:
- '@babel/core': ^7.0.0-0
+ '@babel/core': '>=7.29.6'
'@babel/plugin-syntax-top-level-await@7.14.5':
resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==}
engines: {node: '>=6.9.0'}
peerDependencies:
- '@babel/core': ^7.0.0-0
+ '@babel/core': '>=7.29.6'
'@babel/plugin-syntax-typescript@7.28.6':
resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==}
engines: {node: '>=6.9.0'}
peerDependencies:
- '@babel/core': ^7.0.0-0
+ '@babel/core': '>=7.29.6'
'@babel/runtime@7.28.6':
resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==}
engines: {node: '>=6.9.0'}
- '@babel/template@7.28.6':
- resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==}
- engines: {node: '>=6.9.0'}
+ '@babel/template@8.0.0':
+ resolution: {integrity: sha512-eAD0QW/AlbamBbw0FeGiwasbCVPq5ncW0HNVyLP3B9czqLyh4gvw+5JTSNt6le9+ziAU7mqDZsKTHf3jTb4chQ==}
+ engines: {node: ^22.18.0 || >=24.11.0}
- '@babel/traverse@7.29.0':
- resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==}
- engines: {node: '>=6.9.0'}
+ '@babel/traverse@8.0.0':
+ resolution: {integrity: sha512-bxTj/W2VclGE6CctlfQOpxg8MPDzXArRqkOBePw8EHfebcjF7fETWSS3BriEECo+UiU/Yblq+xUtSImFu7cTbw==}
+ engines: {node: ^22.18.0 || >=24.11.0}
'@babel/types@7.29.0':
resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
engines: {node: '>=6.9.0'}
+ '@babel/types@8.0.0':
+ resolution: {integrity: sha512-K8ponJDxBwDHigkeFqaqT5wLGl4bTlwMafR8k7b5CPxr6Ww+UG9ls8Yx6Tcpboxu97eeGVEEyKcHmEyOwN1vSw==}
+ engines: {node: ^22.18.0 || >=24.11.0}
+
'@bcoe/v8-coverage@0.2.3':
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
@@ -715,57 +749,57 @@ packages:
'@napi-rs/wasm-runtime@0.2.12':
resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==}
- '@next/env@16.1.6':
- resolution: {integrity: sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==}
+ '@next/env@16.2.9':
+ resolution: {integrity: sha512-ki5VxxXfzD/9TDe13wyeTKIjQTAwBVpnr8KhRDUr8ltMUq1/NBpWNT5tiPoxiGl+PHM4X2ahSOiPk6iAimIzPg==}
- '@next/swc-darwin-arm64@16.1.6':
- resolution: {integrity: sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==}
+ '@next/swc-darwin-arm64@16.2.9':
+ resolution: {integrity: sha512-HkfxNYUCmcct0Xsqib5KxqMSHV4AHJq857BNRchyBDs4YS19aHzVfn1kDuBYKqLLQBjXgnkIsjV2Kd4d2wzYhw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
- '@next/swc-darwin-x64@16.1.6':
- resolution: {integrity: sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==}
+ '@next/swc-darwin-x64@16.2.9':
+ resolution: {integrity: sha512-7IAtK4MeybpqRV9GRABWEhJ62mOS+rzWOzOTFie4cSEtm12xsoOMJRcECoZx3FHPzFAqN/IJtHqWAFOLfl152w==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
- '@next/swc-linux-arm64-gnu@16.1.6':
- resolution: {integrity: sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==}
+ '@next/swc-linux-arm64-gnu@16.2.9':
+ resolution: {integrity: sha512-hBD75iWpUtkL9SmQmcRhmLomn9jgkPzCEkbOcLgHymPEKzv+6ONy13RRiIEz/iEObjkS2Jlb5gYS2XGoS3X4rw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [glibc]
- '@next/swc-linux-arm64-musl@16.1.6':
- resolution: {integrity: sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==}
+ '@next/swc-linux-arm64-musl@16.2.9':
+ resolution: {integrity: sha512-qZTI3pf9SGc/obr8NkQAekBxmp1QK+kVm+VAf3BALLfFAj+1kUhkTxmrWpVos9R/UYIA8AWX2p6cGI5WdwzVUA==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [musl]
- '@next/swc-linux-x64-gnu@16.1.6':
- resolution: {integrity: sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==}
+ '@next/swc-linux-x64-gnu@16.2.9':
+ resolution: {integrity: sha512-xm0HfRNX+UkH4R3c18ynswjj5o5uEj/7iI9p9omdtTSIsRCzQqkGMA+10nzJ4EHnYC3as65IMhbbl5fWRUWHYg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [glibc]
- '@next/swc-linux-x64-musl@16.1.6':
- resolution: {integrity: sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==}
+ '@next/swc-linux-x64-musl@16.2.9':
+ resolution: {integrity: sha512-QumimHkGEG6vM3PfEDWKyKen03NcqLOkeKB1EfcPe7VxzmEiCa4jNnMyBn/US5zcd/VE1CI+O8Ovb3lfjVHfGw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [musl]
- '@next/swc-win32-arm64-msvc@16.1.6':
- resolution: {integrity: sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==}
+ '@next/swc-win32-arm64-msvc@16.2.9':
+ resolution: {integrity: sha512-hzQpKZvw8rAwI6A2uQh6SacCSvNAXaIkPNsWwzqqfRiIMiXMfH936skDhz1OO6KpvdKkJrgHHtqQOq5PIXOvdQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
- '@next/swc-win32-x64-msvc@16.1.6':
- resolution: {integrity: sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==}
+ '@next/swc-win32-x64-msvc@16.2.9':
+ resolution: {integrity: sha512-qr2VL3Ce5QrwgO2yh1ujSBawrimjVKX8FGF/cOynmdYKJY0BdHpGVNIRK1tqONB10Vkm25Ub1BD2bkjWs4+96w==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
@@ -983,6 +1017,9 @@ packages:
'@types/draco3d@1.4.10':
resolution: {integrity: sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==}
+ '@types/gensync@1.0.5':
+ resolution: {integrity: sha512-MbsRCT7mTikHwKZ0X+LVUTLRrZZRLipTuXEO9qOYO+zmjMVk81axyClMROf6uoPD9MRVu46bx8zoR0Ad9q3NAg==}
+
'@types/istanbul-lib-coverage@2.0.6':
resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
@@ -998,6 +1035,9 @@ packages:
'@types/jsdom@21.1.7':
resolution: {integrity: sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==}
+ '@types/jsesc@2.5.1':
+ resolution: {integrity: sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==}
+
'@types/node@20.19.11':
resolution: {integrity: sha512-uug3FEEGv0r+jrecvUUpbY8lLisvIjg6AAic6a2bSP5OEOLeJsDSnvhCDov7ipFFMXS3orMpzlmi0ZcuGkBbow==}
@@ -1026,8 +1066,8 @@ packages:
'@types/stats.js@0.17.4':
resolution: {integrity: sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==}
- '@types/three@0.183.1':
- resolution: {integrity: sha512-f2Pu5Hrepfgavttdye3PsH5RWyY/AvdZQwIVhrc4uNtvF7nOWJacQKcoVJn0S4f0yYbmAE6AR+ve7xDcuYtMGw==}
+ '@types/three@0.182.0':
+ resolution: {integrity: sha512-WByN9V3Sbwbe2OkWuSGyoqQO8Du6yhYaXtXLoA5FkKTUJorZ+yOHBZ35zUUPQXlAKABZmbYp5oAqpA4RBjtJ/Q==}
'@types/tough-cookie@4.0.5':
resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==}
@@ -1043,6 +1083,7 @@ packages:
'@ungap/structured-clone@1.3.0':
resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
+ deprecated: Potential CWE-502 - Update to 1.3.1 or higher
'@unrs/resolver-binding-android-arm-eabi@1.11.1':
resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==}
@@ -1202,8 +1243,8 @@ packages:
arg@4.1.3:
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
- argparse@1.0.10:
- resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
+ argparse@2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
aria-query@5.3.0:
resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
@@ -1216,7 +1257,7 @@ packages:
resolution: {integrity: sha512-gRpauEU2KRrCox5Z296aeVHR4jQ98BCnu0IO332D/xpHNOsIH/bgSRk9k6GbKIbBw8vFeN6ctuu6tV8WOyVfYQ==}
engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
peerDependencies:
- '@babel/core': ^7.11.0 || ^8.0.0-0
+ '@babel/core': '>=7.29.6'
babel-plugin-istanbul@7.0.1:
resolution: {integrity: sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==}
@@ -1229,17 +1270,21 @@ packages:
babel-preset-current-node-syntax@1.2.0:
resolution: {integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==}
peerDependencies:
- '@babel/core': ^7.0.0 || ^8.0.0-0
+ '@babel/core': '>=7.29.6'
babel-preset-jest@30.3.0:
resolution: {integrity: sha512-6ZcUbWHC+dMz2vfzdNwi87Z1gQsLNK2uLuK1Q89R11xdvejcivlYYwDlEv0FHX3VwEXpbBQ9uufB/MUNpZGfhQ==}
engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
peerDependencies:
- '@babel/core': ^7.11.0 || ^8.0.0-beta.1
+ '@babel/core': '>=7.29.6'
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+ balanced-match@4.0.4:
+ resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
+ engines: {node: 18 || 20 || >=22}
+
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
@@ -1251,12 +1296,13 @@ packages:
bidi-js@1.0.3:
resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==}
- brace-expansion@1.1.12:
- resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==}
-
brace-expansion@2.0.2:
resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
+ brace-expansion@5.0.6:
+ resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==}
+ engines: {node: 18 || 20 || >=22}
+
browserslist@4.28.1:
resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
@@ -1293,9 +1339,6 @@ packages:
peerDependencies:
three: '>=0.126.1'
- caniuse-lite@1.0.30001739:
- resolution: {integrity: sha512-y+j60d6ulelrNSwpPyrHdl+9mJnQzHBr08xm48Qno0nSk4h3Qojh+ziv2qE6rXf4k3tadF4o1J/1tAbVm1NtnA==}
-
caniuse-lite@1.0.30001777:
resolution: {integrity: sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==}
@@ -1349,9 +1392,6 @@ packages:
color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
- concat-map@0.0.1:
- resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
-
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
@@ -1453,6 +1493,10 @@ packages:
emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+ empathic@2.0.1:
+ resolution: {integrity: sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q==}
+ engines: {node: '>=14'}
+
enhanced-resolve@5.18.3:
resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==}
engines: {node: '>=10.13.0'}
@@ -1472,11 +1516,6 @@ packages:
resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}
engines: {node: '>=8'}
- esprima@4.0.1:
- resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
- engines: {node: '>=4'}
- hasBin: true
-
execa@5.1.1:
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
engines: {node: '>=10'}
@@ -1569,8 +1608,8 @@ packages:
gsap@3.13.0:
resolution: {integrity: sha512-QL7MJ2WMjm1PHWsoFrAQH/J8wUeqZvMtHO58qdekHpCfhvhSL4gSiz6vJf5EeMP0LOn3ZCprL2ki/gjED8ghVw==}
- handlebars@4.7.8:
- resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==}
+ handlebars@4.7.9:
+ resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==}
engines: {node: '>=0.4.7'}
hasBin: true
@@ -1622,6 +1661,9 @@ packages:
engines: {node: '>=8'}
hasBin: true
+ import-meta-resolve@4.2.0:
+ resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==}
+
imurmurhash@0.1.4:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
@@ -1830,11 +1872,14 @@ packages:
resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==}
hasBin: true
+ js-tokens@10.0.0:
+ resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==}
+
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
- js-yaml@3.14.2:
- resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==}
+ js-yaml@5.1.0:
+ resolution: {integrity: sha512-s8VA5jkR8f22S3NAXmhKPFqGUduqZGlsufabVOgN14iTdw/RXcym7bKkbwjxLK9Yw2lEvvmJjFp119+KPeo8Kg==}
hasBin: true
jsdom@26.1.0:
@@ -1961,8 +2006,9 @@ packages:
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
- lru-cache@5.1.1:
- resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+ lru-cache@11.5.1:
+ resolution: {integrity: sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==}
+ engines: {node: 20 || >=22}
lucide-react@0.542.0:
resolution: {integrity: sha512-w3hD8/SQB7+lzU2r4VdFyzzOzKnUjTZIF/MQJGSSvni7Llewni4vuViRppfRAa2guOsY5k4jZyxw/i9DQHv+dw==}
@@ -2000,8 +2046,8 @@ packages:
peerDependencies:
three: '>=0.137'
- meshoptimizer@1.0.1:
- resolution: {integrity: sha512-Vix+QlA1YYT3FwmBBZ+49cE5y/b+pRrcXKqGpS5ouh33d3lSp2PoTpCw19E0cKDFWalembrHnIaZetf27a+W2g==}
+ meshoptimizer@0.22.0:
+ resolution: {integrity: sha512-IebiK79sqIy+E4EgOr+CAw+Ke8hAspXKzBd0JdgEmPHiAwmvEj2S4h1rfvo+o/BnfEYd/jAOg5IeeIjzlzSnDg==}
mimic-fn@2.1.0:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
@@ -2052,8 +2098,8 @@ packages:
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
- nanoid@3.3.11:
- resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+ nanoid@3.3.15:
+ resolution: {integrity: sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
@@ -2068,8 +2114,8 @@ packages:
neo-async@2.6.2:
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
- next@16.1.6:
- resolution: {integrity: sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==}
+ next@16.2.9:
+ resolution: {integrity: sha512-MEOJiq/UvuezAdqVSceHbqDgZt1kDw2tpGVOlsdIoJsQdbN2JY2hpVG4xnXGkbdJUOEWhnRfiu/O4Hpc9Juwww==}
engines: {node: '>=20.9.0'}
hasBin: true
peerDependencies:
@@ -2106,6 +2152,10 @@ packages:
nwsapi@2.2.23:
resolution: {integrity: sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==}
+ obug@2.1.3:
+ resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==}
+ engines: {node: '>=12.20.0'}
+
ogl@1.0.11:
resolution: {integrity: sha512-kUpC154AFfxi16pmZUK4jk3J+8zxwTWGPo03EoYA8QPbzikHoaC82n6pNTbd+oEaJonaE8aPWBlX7ad9zrqLsA==}
@@ -2164,12 +2214,8 @@ packages:
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
- picomatch@2.3.1:
- resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
- engines: {node: '>=8.6'}
-
- picomatch@4.0.3:
- resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
+ picomatch@4.0.4:
+ resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
engines: {node: '>=12'}
pirates@4.0.7:
@@ -2180,12 +2226,8 @@ packages:
resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
engines: {node: '>=8'}
- postcss@8.4.31:
- resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
- engines: {node: ^10 || ^12 || >=14}
-
- postcss@8.5.6:
- resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
+ postcss@8.5.15:
+ resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
engines: {node: ^10 || ^12 || >=14}
potpack@1.0.2:
@@ -2275,10 +2317,6 @@ packages:
scheduler@0.27.0:
resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
- semver@6.3.1:
- resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
- hasBin: true
-
semver@7.7.4:
resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
engines: {node: '>=10'}
@@ -2318,9 +2356,6 @@ packages:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
- sprintf-js@1.0.3:
- resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
-
stack-utils@2.0.6:
resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
engines: {node: '>=10'}
@@ -2436,8 +2471,8 @@ packages:
peerDependencies:
three: '>=0.128.0'
- three@0.183.2:
- resolution: {integrity: sha512-di3BsL2FEQ1PA7Hcvn4fyJOlxRRgFYBpMTcyOgkwJIaDOdJMebEFPA+t98EvjuljDx4hNulAGwF6KIjtwI5jgQ==}
+ three@0.182.0:
+ resolution: {integrity: sha512-GbHabT+Irv+ihI1/f5kIIsZ+Ef9Sl5A1Y7imvS5RQjWgtTPfPnZ43JmlYI7NtCRDK9zir20lQpfg8/9Yd02OvQ==}
tldts-core@6.1.86:
resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==}
@@ -2475,7 +2510,7 @@ packages:
engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
- '@babel/core': '>=7.0.0-beta.0 <8'
+ '@babel/core': '>=7.29.6'
'@jest/transform': ^29.0.0 || ^30.0.0
'@jest/types': ^29.0.0 || ^30.0.0
babel-jest: ^29.0.0 || ^30.0.0
@@ -2623,8 +2658,8 @@ packages:
resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
- ws@8.19.0:
- resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==}
+ ws@8.21.0:
+ resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
@@ -2646,9 +2681,6 @@ packages:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
- yallist@3.1.1:
- resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
-
yallist@5.0.0:
resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
engines: {node: '>=18'}
@@ -2722,27 +2754,31 @@ snapshots:
js-tokens: 4.0.0
picocolors: 1.1.1
- '@babel/compat-data@7.29.0': {}
-
- '@babel/core@7.29.0':
+ '@babel/code-frame@8.0.0':
dependencies:
- '@babel/code-frame': 7.29.0
- '@babel/generator': 7.29.1
- '@babel/helper-compilation-targets': 7.28.6
- '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0)
- '@babel/helpers': 7.28.6
- '@babel/parser': 7.29.0
- '@babel/template': 7.28.6
- '@babel/traverse': 7.29.0
- '@babel/types': 7.29.0
- '@jridgewell/remapping': 2.3.5
+ '@babel/helper-validator-identifier': 8.0.2
+ js-tokens: 10.0.0
+
+ '@babel/compat-data@8.0.0': {}
+
+ '@babel/core@8.0.1':
+ dependencies:
+ '@babel/code-frame': 8.0.0
+ '@babel/generator': 8.0.0
+ '@babel/helper-compilation-targets': 8.0.0
+ '@babel/helpers': 8.0.0
+ '@babel/parser': 8.0.0
+ '@babel/template': 8.0.0
+ '@babel/traverse': 8.0.0
+ '@babel/types': 8.0.0
+ '@types/gensync': 1.0.5
convert-source-map: 2.0.0
- debug: 4.4.3
+ empathic: 2.0.1
gensync: 1.0.0-beta.2
+ import-meta-resolve: 4.2.0
json5: 2.2.3
- semver: 6.3.1
- transitivePeerDependencies:
- - supports-color
+ obug: 2.1.3
+ semver: 7.7.4
'@babel/generator@7.29.1':
dependencies:
@@ -2752,159 +2788,163 @@ snapshots:
'@jridgewell/trace-mapping': 0.3.30
jsesc: 3.1.0
- '@babel/helper-compilation-targets@7.28.6':
+ '@babel/generator@8.0.0':
dependencies:
- '@babel/compat-data': 7.29.0
- '@babel/helper-validator-option': 7.27.1
+ '@babel/parser': 8.0.0
+ '@babel/types': 8.0.0
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.30
+ '@types/jsesc': 2.5.1
+ jsesc: 3.1.0
+
+ '@babel/helper-compilation-targets@8.0.0':
+ dependencies:
+ '@babel/compat-data': 8.0.0
+ '@babel/helper-validator-option': 8.0.0
browserslist: 4.28.1
- lru-cache: 5.1.1
- semver: 6.3.1
+ lru-cache: 11.5.1
+ semver: 7.7.4
- '@babel/helper-globals@7.28.0': {}
-
- '@babel/helper-module-imports@7.28.6':
- dependencies:
- '@babel/traverse': 7.29.0
- '@babel/types': 7.29.0
- transitivePeerDependencies:
- - supports-color
-
- '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-module-imports': 7.28.6
- '@babel/helper-validator-identifier': 7.28.5
- '@babel/traverse': 7.29.0
- transitivePeerDependencies:
- - supports-color
+ '@babel/helper-globals@8.0.0': {}
'@babel/helper-plugin-utils@7.28.6': {}
'@babel/helper-string-parser@7.27.1': {}
+ '@babel/helper-string-parser@8.0.0': {}
+
'@babel/helper-validator-identifier@7.28.5': {}
- '@babel/helper-validator-option@7.27.1': {}
+ '@babel/helper-validator-identifier@8.0.2': {}
- '@babel/helpers@7.28.6':
+ '@babel/helper-validator-option@8.0.0': {}
+
+ '@babel/helpers@8.0.0':
dependencies:
- '@babel/template': 7.28.6
- '@babel/types': 7.29.0
+ '@babel/template': 8.0.0
+ '@babel/types': 8.0.0
'@babel/parser@7.29.0':
dependencies:
'@babel/types': 7.29.0
- '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.0)':
+ '@babel/parser@8.0.0':
dependencies:
- '@babel/core': 7.29.0
+ '@babel/types': 8.0.0
+
+ '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@8.0.1)':
+ dependencies:
+ '@babel/core': 8.0.1
'@babel/helper-plugin-utils': 7.28.6
- '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.0)':
+ '@babel/plugin-syntax-bigint@7.8.3(@babel/core@8.0.1)':
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@babel/helper-plugin-utils': 7.28.6
- '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.0)':
+ '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@8.0.1)':
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@babel/helper-plugin-utils': 7.28.6
- '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.0)':
+ '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@8.0.1)':
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@babel/helper-plugin-utils': 7.28.6
- '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)':
+ '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@8.0.1)':
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@babel/helper-plugin-utils': 7.28.6
- '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)':
+ '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@8.0.1)':
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@babel/helper-plugin-utils': 7.28.6
- '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.0)':
+ '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@8.0.1)':
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@babel/helper-plugin-utils': 7.28.6
- '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)':
+ '@babel/plugin-syntax-jsx@7.28.6(@babel/core@8.0.1)':
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@babel/helper-plugin-utils': 7.28.6
- '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.0)':
+ '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@8.0.1)':
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@babel/helper-plugin-utils': 7.28.6
- '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.0)':
+ '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@8.0.1)':
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@babel/helper-plugin-utils': 7.28.6
- '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.0)':
+ '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@8.0.1)':
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@babel/helper-plugin-utils': 7.28.6
- '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.0)':
+ '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@8.0.1)':
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@babel/helper-plugin-utils': 7.28.6
- '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.0)':
+ '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@8.0.1)':
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@babel/helper-plugin-utils': 7.28.6
- '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.0)':
+ '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@8.0.1)':
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@babel/helper-plugin-utils': 7.28.6
- '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.0)':
+ '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@8.0.1)':
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@babel/helper-plugin-utils': 7.28.6
- '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.0)':
+ '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@8.0.1)':
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@babel/helper-plugin-utils': 7.28.6
- '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)':
+ '@babel/plugin-syntax-typescript@7.28.6(@babel/core@8.0.1)':
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@babel/helper-plugin-utils': 7.28.6
'@babel/runtime@7.28.6': {}
- '@babel/template@7.28.6':
+ '@babel/template@8.0.0':
dependencies:
- '@babel/code-frame': 7.29.0
- '@babel/parser': 7.29.0
- '@babel/types': 7.29.0
+ '@babel/code-frame': 8.0.0
+ '@babel/parser': 8.0.0
+ '@babel/types': 8.0.0
- '@babel/traverse@7.29.0':
+ '@babel/traverse@8.0.0':
dependencies:
- '@babel/code-frame': 7.29.0
- '@babel/generator': 7.29.1
- '@babel/helper-globals': 7.28.0
- '@babel/parser': 7.29.0
- '@babel/template': 7.28.6
- '@babel/types': 7.29.0
- debug: 4.4.3
- transitivePeerDependencies:
- - supports-color
+ '@babel/code-frame': 8.0.0
+ '@babel/generator': 8.0.0
+ '@babel/helper-globals': 8.0.0
+ '@babel/parser': 8.0.0
+ '@babel/template': 8.0.0
+ '@babel/types': 8.0.0
+ obug: 2.1.3
'@babel/types@7.29.0':
dependencies:
'@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.28.5
+ '@babel/types@8.0.0':
+ dependencies:
+ '@babel/helper-string-parser': 8.0.0
+ '@babel/helper-validator-identifier': 8.0.2
+
'@bcoe/v8-coverage@0.2.3': {}
'@biomejs/biome@2.2.0':
@@ -3104,7 +3144,7 @@ snapshots:
camelcase: 5.3.1
find-up: 4.1.0
get-package-type: 0.1.0
- js-yaml: 3.14.2
+ js-yaml: 5.1.0
resolve-from: 5.0.0
'@istanbuljs/schema@0.1.3': {}
@@ -3181,8 +3221,6 @@ snapshots:
dependencies:
expect: 30.3.0
jest-snapshot: 30.3.0
- transitivePeerDependencies:
- - supports-color
'@jest/fake-timers@30.3.0':
dependencies:
@@ -3201,8 +3239,6 @@ snapshots:
'@jest/expect': 30.3.0
'@jest/types': 30.3.0
jest-mock: 30.3.0
- transitivePeerDependencies:
- - supports-color
'@jest/pattern@30.0.1':
dependencies:
@@ -3270,7 +3306,7 @@ snapshots:
'@jest/transform@30.3.0':
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@jest/types': 30.3.0
'@jridgewell/trace-mapping': 0.3.30
babel-plugin-istanbul: 7.0.1
@@ -3284,8 +3320,6 @@ snapshots:
pirates: 4.0.7
slash: 3.0.0
write-file-atomic: 5.0.1
- transitivePeerDependencies:
- - supports-color
'@jest/types@30.3.0':
dependencies:
@@ -3323,10 +3357,10 @@ snapshots:
'@mediapipe/tasks-vision@0.10.17': {}
- '@monogrid/gainmap-js@3.4.0(three@0.183.2)':
+ '@monogrid/gainmap-js@3.4.0(three@0.182.0)':
dependencies:
promise-worker-transferable: 1.0.4
- three: 0.183.2
+ three: 0.182.0
'@napi-rs/wasm-runtime@0.2.12':
dependencies:
@@ -3335,30 +3369,30 @@ snapshots:
'@tybys/wasm-util': 0.10.1
optional: true
- '@next/env@16.1.6': {}
+ '@next/env@16.2.9': {}
- '@next/swc-darwin-arm64@16.1.6':
+ '@next/swc-darwin-arm64@16.2.9':
optional: true
- '@next/swc-darwin-x64@16.1.6':
+ '@next/swc-darwin-x64@16.2.9':
optional: true
- '@next/swc-linux-arm64-gnu@16.1.6':
+ '@next/swc-linux-arm64-gnu@16.2.9':
optional: true
- '@next/swc-linux-arm64-musl@16.1.6':
+ '@next/swc-linux-arm64-musl@16.2.9':
optional: true
- '@next/swc-linux-x64-gnu@16.1.6':
+ '@next/swc-linux-x64-gnu@16.2.9':
optional: true
- '@next/swc-linux-x64-musl@16.1.6':
+ '@next/swc-linux-x64-musl@16.2.9':
optional: true
- '@next/swc-win32-arm64-msvc@16.1.6':
+ '@next/swc-win32-arm64-msvc@16.2.9':
optional: true
- '@next/swc-win32-x64-msvc@16.1.6':
+ '@next/swc-win32-x64-msvc@16.2.9':
optional: true
'@pkgjs/parseargs@0.11.0':
@@ -3366,28 +3400,28 @@ snapshots:
'@pkgr/core@0.2.9': {}
- '@react-three/drei@10.7.7(@react-three/fiber@9.5.0(@types/react@19.1.12)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.183.2))(@types/react@19.1.12)(@types/three@0.183.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.183.2)':
+ '@react-three/drei@10.7.7(@react-three/fiber@9.5.0(@types/react@19.1.12)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.182.0))(@types/react@19.1.12)(@types/three@0.182.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.182.0)':
dependencies:
'@babel/runtime': 7.28.6
'@mediapipe/tasks-vision': 0.10.17
- '@monogrid/gainmap-js': 3.4.0(three@0.183.2)
- '@react-three/fiber': 9.5.0(@types/react@19.1.12)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.183.2)
+ '@monogrid/gainmap-js': 3.4.0(three@0.182.0)
+ '@react-three/fiber': 9.5.0(@types/react@19.1.12)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.182.0)
'@use-gesture/react': 10.3.1(react@19.1.0)
- camera-controls: 3.1.2(three@0.183.2)
+ camera-controls: 3.1.2(three@0.182.0)
cross-env: 7.0.3
detect-gpu: 5.0.70
glsl-noise: 0.0.0
hls.js: 1.6.15
- maath: 0.10.8(@types/three@0.183.1)(three@0.183.2)
- meshline: 3.3.1(three@0.183.2)
+ maath: 0.10.8(@types/three@0.182.0)(three@0.182.0)
+ meshline: 3.3.1(three@0.182.0)
react: 19.1.0
- stats-gl: 2.4.2(@types/three@0.183.1)(three@0.183.2)
+ stats-gl: 2.4.2(@types/three@0.182.0)(three@0.182.0)
stats.js: 0.17.0
suspend-react: 0.1.3(react@19.1.0)
- three: 0.183.2
- three-mesh-bvh: 0.8.3(three@0.183.2)
- three-stdlib: 2.36.1(three@0.183.2)
- troika-three-text: 0.52.4(three@0.183.2)
+ three: 0.182.0
+ three-mesh-bvh: 0.8.3(three@0.182.0)
+ three-stdlib: 2.36.1(three@0.182.0)
+ troika-three-text: 0.52.4(three@0.182.0)
tunnel-rat: 0.1.2(@types/react@19.1.12)(react@19.1.0)
use-sync-external-store: 1.6.0(react@19.1.0)
utility-types: 3.11.0
@@ -3399,7 +3433,7 @@ snapshots:
- '@types/three'
- immer
- '@react-three/fiber@9.5.0(@types/react@19.1.12)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.183.2)':
+ '@react-three/fiber@9.5.0(@types/react@19.1.12)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(three@0.182.0)':
dependencies:
'@babel/runtime': 7.28.6
'@types/webxr': 0.5.24
@@ -3410,7 +3444,7 @@ snapshots:
react-use-measure: 2.1.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
scheduler: 0.27.0
suspend-react: 0.1.3(react@19.1.0)
- three: 0.183.2
+ three: 0.182.0
use-sync-external-store: 1.6.0(react@19.1.0)
zustand: 5.0.11(@types/react@19.1.12)(react@19.1.0)(use-sync-external-store@1.6.0(react@19.1.0))
optionalDependencies:
@@ -3502,7 +3536,7 @@ snapshots:
'@alloc/quick-lru': 5.2.0
'@tailwindcss/node': 4.1.12
'@tailwindcss/oxide': 4.1.12
- postcss: 8.5.6
+ postcss: 8.5.15
tailwindcss: 4.1.12
'@testing-library/dom@10.4.1':
@@ -3579,6 +3613,8 @@ snapshots:
'@types/draco3d@1.4.10': {}
+ '@types/gensync@1.0.5': {}
+
'@types/istanbul-lib-coverage@2.0.6': {}
'@types/istanbul-lib-report@3.0.3':
@@ -3600,6 +3636,8 @@ snapshots:
'@types/tough-cookie': 4.0.5
parse5: 7.3.0
+ '@types/jsesc@2.5.1': {}
+
'@types/node@20.19.11':
dependencies:
undici-types: 6.21.0
@@ -3624,7 +3662,7 @@ snapshots:
'@types/stats.js@0.17.4': {}
- '@types/three@0.183.1':
+ '@types/three@0.182.0':
dependencies:
'@dimforge/rapier3d-compat': 0.12.0
'@tweenjs/tween.js': 23.1.3
@@ -3632,7 +3670,7 @@ snapshots:
'@types/webxr': 0.5.24
'@webgpu/types': 0.1.69
fflate: 0.8.2
- meshoptimizer: 1.0.1
+ meshoptimizer: 0.22.0
'@types/tough-cookie@4.0.5': {}
@@ -3741,13 +3779,11 @@ snapshots:
anymatch@3.1.3:
dependencies:
normalize-path: 3.0.0
- picomatch: 2.3.1
+ picomatch: 4.0.4
arg@4.1.3: {}
- argparse@1.0.10:
- dependencies:
- sprintf-js: 1.0.3
+ argparse@2.0.1: {}
aria-query@5.3.0:
dependencies:
@@ -3755,18 +3791,16 @@ snapshots:
aria-query@5.3.2: {}
- babel-jest@30.3.0(@babel/core@7.29.0):
+ babel-jest@30.3.0(@babel/core@8.0.1):
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@jest/transform': 30.3.0
'@types/babel__core': 7.20.5
babel-plugin-istanbul: 7.0.1
- babel-preset-jest: 30.3.0(@babel/core@7.29.0)
+ babel-preset-jest: 30.3.0(@babel/core@8.0.1)
chalk: 4.1.2
graceful-fs: 4.2.11
slash: 3.0.0
- transitivePeerDependencies:
- - supports-color
babel-plugin-istanbul@7.0.1:
dependencies:
@@ -3775,40 +3809,40 @@ snapshots:
'@istanbuljs/schema': 0.1.3
istanbul-lib-instrument: 6.0.3
test-exclude: 6.0.0
- transitivePeerDependencies:
- - supports-color
babel-plugin-jest-hoist@30.3.0:
dependencies:
'@types/babel__core': 7.20.5
- babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.0):
+ babel-preset-current-node-syntax@1.2.0(@babel/core@8.0.1):
dependencies:
- '@babel/core': 7.29.0
- '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.0)
- '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.0)
- '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.0)
- '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.0)
- '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0)
- '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0)
- '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.0)
- '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.0)
- '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0)
- '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.0)
- '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.0)
- '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.0)
- '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0)
- '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.0)
- '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.0)
+ '@babel/core': 8.0.1
+ '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@8.0.1)
+ '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@8.0.1)
+ '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@8.0.1)
+ '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@8.0.1)
+ '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@8.0.1)
+ '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@8.0.1)
+ '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@8.0.1)
+ '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@8.0.1)
+ '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@8.0.1)
+ '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@8.0.1)
+ '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@8.0.1)
+ '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@8.0.1)
+ '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@8.0.1)
+ '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@8.0.1)
+ '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@8.0.1)
- babel-preset-jest@30.3.0(@babel/core@7.29.0):
+ babel-preset-jest@30.3.0(@babel/core@8.0.1):
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
babel-plugin-jest-hoist: 30.3.0
- babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0)
+ babel-preset-current-node-syntax: 1.2.0(@babel/core@8.0.1)
balanced-match@1.0.2: {}
+ balanced-match@4.0.4: {}
+
base64-js@1.5.1: {}
baseline-browser-mapping@2.10.0: {}
@@ -3817,15 +3851,14 @@ snapshots:
dependencies:
require-from-string: 2.0.2
- brace-expansion@1.1.12:
- dependencies:
- balanced-match: 1.0.2
- concat-map: 0.0.1
-
brace-expansion@2.0.2:
dependencies:
balanced-match: 1.0.2
+ brace-expansion@5.0.6:
+ dependencies:
+ balanced-match: 4.0.4
+
browserslist@4.28.1:
dependencies:
baseline-browser-mapping: 2.10.0
@@ -3855,11 +3888,9 @@ snapshots:
camelcase@6.3.0: {}
- camera-controls@3.1.2(three@0.183.2):
+ camera-controls@3.1.2(three@0.182.0):
dependencies:
- three: 0.183.2
-
- caniuse-lite@1.0.30001739: {}
+ three: 0.182.0
caniuse-lite@1.0.30001777: {}
@@ -3904,8 +3935,6 @@ snapshots:
color-name@1.1.4: {}
- concat-map@0.0.1: {}
-
convert-source-map@2.0.0: {}
create-require@1.1.1: {}
@@ -3975,6 +4004,8 @@ snapshots:
emoji-regex@9.2.2: {}
+ empathic@2.0.1: {}
+
enhanced-resolve@5.18.3:
dependencies:
graceful-fs: 4.2.11
@@ -3990,8 +4021,6 @@ snapshots:
escape-string-regexp@2.0.0: {}
- esprima@4.0.1: {}
-
execa@5.1.1:
dependencies:
cross-spawn: 7.0.6
@@ -4085,7 +4114,7 @@ snapshots:
gsap@3.13.0: {}
- handlebars@4.7.8:
+ handlebars@4.7.9:
dependencies:
minimist: 1.2.8
neo-async: 2.6.2
@@ -4139,6 +4168,8 @@ snapshots:
pkg-dir: 4.2.0
resolve-cwd: 3.0.0
+ import-meta-resolve@4.2.0: {}
+
imurmurhash@0.1.4: {}
indent-string@4.0.0: {}
@@ -4168,13 +4199,11 @@ snapshots:
istanbul-lib-instrument@6.0.3:
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@babel/parser': 7.29.0
'@istanbuljs/schema': 0.1.3
istanbul-lib-coverage: 3.2.2
semver: 7.7.4
- transitivePeerDependencies:
- - supports-color
istanbul-lib-report@3.0.1:
dependencies:
@@ -4238,7 +4267,6 @@ snapshots:
stack-utils: 2.0.6
transitivePeerDependencies:
- babel-plugin-macros
- - supports-color
jest-cli@30.3.0(@types/node@20.19.11)(ts-node@10.9.2(@types/node@20.19.11)(typescript@5.9.2)):
dependencies:
@@ -4261,12 +4289,12 @@ snapshots:
jest-config@30.3.0(@types/node@20.19.11)(ts-node@10.9.2(@types/node@20.19.11)(typescript@5.9.2)):
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@jest/get-type': 30.1.0
'@jest/pattern': 30.0.1
'@jest/test-sequencer': 30.3.0
'@jest/types': 30.3.0
- babel-jest: 30.3.0(@babel/core@7.29.0)
+ babel-jest: 30.3.0(@babel/core@8.0.1)
chalk: 4.1.2
ci-info: 4.4.0
deepmerge: 4.3.1
@@ -4289,7 +4317,6 @@ snapshots:
ts-node: 10.9.2(@types/node@20.19.11)(typescript@5.9.2)
transitivePeerDependencies:
- babel-plugin-macros
- - supports-color
jest-diff@30.3.0:
dependencies:
@@ -4340,7 +4367,7 @@ snapshots:
jest-regex-util: 30.0.1
jest-util: 30.3.0
jest-worker: 30.3.0
- picomatch: 4.0.3
+ picomatch: 4.0.4
walker: 1.0.8
optionalDependencies:
fsevents: 2.3.3
@@ -4364,7 +4391,7 @@ snapshots:
'@types/stack-utils': 2.0.3
chalk: 4.1.2
graceful-fs: 4.2.11
- picomatch: 4.0.3
+ picomatch: 4.0.4
pretty-format: 30.3.0
slash: 3.0.0
stack-utils: 2.0.6
@@ -4385,8 +4412,6 @@ snapshots:
dependencies:
jest-regex-util: 30.0.1
jest-snapshot: 30.3.0
- transitivePeerDependencies:
- - supports-color
jest-resolve@30.3.0:
dependencies:
@@ -4423,8 +4448,6 @@ snapshots:
jest-worker: 30.3.0
p-limit: 3.1.0
source-map-support: 0.5.13
- transitivePeerDependencies:
- - supports-color
jest-runtime@30.3.0:
dependencies:
@@ -4450,22 +4473,20 @@ snapshots:
jest-util: 30.3.0
slash: 3.0.0
strip-bom: 4.0.0
- transitivePeerDependencies:
- - supports-color
jest-snapshot@30.3.0:
dependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@babel/generator': 7.29.1
- '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0)
- '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0)
+ '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@8.0.1)
+ '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@8.0.1)
'@babel/types': 7.29.0
'@jest/expect-utils': 30.3.0
'@jest/get-type': 30.1.0
'@jest/snapshot-utils': 30.3.0
'@jest/transform': 30.3.0
'@jest/types': 30.3.0
- babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0)
+ babel-preset-current-node-syntax: 1.2.0(@babel/core@8.0.1)
chalk: 4.1.2
expect: 30.3.0
graceful-fs: 4.2.11
@@ -4476,8 +4497,6 @@ snapshots:
pretty-format: 30.3.0
semver: 7.7.4
synckit: 0.11.12
- transitivePeerDependencies:
- - supports-color
jest-util@30.3.0:
dependencies:
@@ -4486,7 +4505,7 @@ snapshots:
chalk: 4.1.2
ci-info: 4.4.0
graceful-fs: 4.2.11
- picomatch: 4.0.3
+ picomatch: 4.0.4
jest-validate@30.3.0:
dependencies:
@@ -4531,12 +4550,13 @@ snapshots:
jiti@2.5.1: {}
+ js-tokens@10.0.0: {}
+
js-tokens@4.0.0: {}
- js-yaml@3.14.2:
+ js-yaml@5.1.0:
dependencies:
- argparse: 1.0.10
- esprima: 4.0.1
+ argparse: 2.0.1
jsdom@26.1.0:
dependencies:
@@ -4558,7 +4578,7 @@ snapshots:
whatwg-encoding: 3.1.1
whatwg-mimetype: 4.0.0
whatwg-url: 14.2.0
- ws: 8.19.0
+ ws: 8.21.0
xml-name-validator: 5.0.0
transitivePeerDependencies:
- bufferutil
@@ -4636,9 +4656,7 @@ snapshots:
lru-cache@10.4.3: {}
- lru-cache@5.1.1:
- dependencies:
- yallist: 3.1.1
+ lru-cache@11.5.1: {}
lucide-react@0.542.0(react@19.1.0):
dependencies:
@@ -4646,10 +4664,10 @@ snapshots:
lz-string@1.5.0: {}
- maath@0.10.8(@types/three@0.183.1)(three@0.183.2):
+ maath@0.10.8(@types/three@0.182.0)(three@0.182.0):
dependencies:
- '@types/three': 0.183.1
- three: 0.183.2
+ '@types/three': 0.182.0
+ three: 0.182.0
magic-string@0.30.18:
dependencies:
@@ -4667,11 +4685,11 @@ snapshots:
merge-stream@2.0.0: {}
- meshline@3.3.1(three@0.183.2):
+ meshline@3.3.1(three@0.182.0):
dependencies:
- three: 0.183.2
+ three: 0.182.0
- meshoptimizer@1.0.1: {}
+ meshoptimizer@0.22.0: {}
mimic-fn@2.1.0: {}
@@ -4679,11 +4697,11 @@ snapshots:
minimatch@3.1.5:
dependencies:
- brace-expansion: 1.1.12
+ brace-expansion: 2.0.2
minimatch@9.0.9:
dependencies:
- brace-expansion: 2.0.2
+ brace-expansion: 5.0.6
minimist@1.2.8: {}
@@ -4709,7 +4727,7 @@ snapshots:
ms@2.1.3: {}
- nanoid@3.3.11: {}
+ nanoid@3.3.15: {}
napi-postinstall@0.3.4: {}
@@ -4717,25 +4735,25 @@ snapshots:
neo-async@2.6.2: {}
- next@16.1.6(@babel/core@7.29.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
+ next@16.2.9(@babel/core@8.0.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
dependencies:
- '@next/env': 16.1.6
+ '@next/env': 16.2.9
'@swc/helpers': 0.5.15
baseline-browser-mapping: 2.10.0
- caniuse-lite: 1.0.30001739
- postcss: 8.4.31
+ caniuse-lite: 1.0.30001777
+ postcss: 8.5.15
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
- styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.1.0)
+ styled-jsx: 5.1.6(@babel/core@8.0.1)(react@19.1.0)
optionalDependencies:
- '@next/swc-darwin-arm64': 16.1.6
- '@next/swc-darwin-x64': 16.1.6
- '@next/swc-linux-arm64-gnu': 16.1.6
- '@next/swc-linux-arm64-musl': 16.1.6
- '@next/swc-linux-x64-gnu': 16.1.6
- '@next/swc-linux-x64-musl': 16.1.6
- '@next/swc-win32-arm64-msvc': 16.1.6
- '@next/swc-win32-x64-msvc': 16.1.6
+ '@next/swc-darwin-arm64': 16.2.9
+ '@next/swc-darwin-x64': 16.2.9
+ '@next/swc-linux-arm64-gnu': 16.2.9
+ '@next/swc-linux-arm64-musl': 16.2.9
+ '@next/swc-linux-x64-gnu': 16.2.9
+ '@next/swc-linux-x64-musl': 16.2.9
+ '@next/swc-win32-arm64-msvc': 16.2.9
+ '@next/swc-win32-x64-msvc': 16.2.9
sharp: 0.34.5
transitivePeerDependencies:
- '@babel/core'
@@ -4753,6 +4771,8 @@ snapshots:
nwsapi@2.2.23: {}
+ obug@2.1.3: {}
+
ogl@1.0.11: {}
once@1.4.0:
@@ -4805,9 +4825,7 @@ snapshots:
picocolors@1.1.1: {}
- picomatch@2.3.1: {}
-
- picomatch@4.0.3: {}
+ picomatch@4.0.4: {}
pirates@4.0.7: {}
@@ -4815,15 +4833,9 @@ snapshots:
dependencies:
find-up: 4.1.0
- postcss@8.4.31:
+ postcss@8.5.15:
dependencies:
- nanoid: 3.3.11
- picocolors: 1.1.1
- source-map-js: 1.2.1
-
- postcss@8.5.6:
- dependencies:
- nanoid: 3.3.11
+ nanoid: 3.3.15
picocolors: 1.1.1
source-map-js: 1.2.1
@@ -4898,8 +4910,6 @@ snapshots:
scheduler@0.27.0: {}
- semver@6.3.1: {}
-
semver@7.7.4: {}
sharp@0.34.5:
@@ -4955,16 +4965,14 @@ snapshots:
source-map@0.6.1: {}
- sprintf-js@1.0.3: {}
-
stack-utils@2.0.6:
dependencies:
escape-string-regexp: 2.0.0
- stats-gl@2.4.2(@types/three@0.183.1)(three@0.183.2):
+ stats-gl@2.4.2(@types/three@0.182.0)(three@0.182.0):
dependencies:
- '@types/three': 0.183.1
- three: 0.183.2
+ '@types/three': 0.182.0
+ three: 0.182.0
stats.js@0.17.0: {}
@@ -5003,12 +5011,12 @@ snapshots:
strip-json-comments@3.1.1: {}
- styled-jsx@5.1.6(@babel/core@7.29.0)(react@19.1.0):
+ styled-jsx@5.1.6(@babel/core@8.0.1)(react@19.1.0):
dependencies:
client-only: 0.0.1
react: 19.1.0
optionalDependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
supports-color@7.2.0:
dependencies:
@@ -5052,11 +5060,11 @@ snapshots:
glob: 7.2.3
minimatch: 3.1.5
- three-mesh-bvh@0.8.3(three@0.183.2):
+ three-mesh-bvh@0.8.3(three@0.182.0):
dependencies:
- three: 0.183.2
+ three: 0.182.0
- three-stdlib@2.36.1(three@0.183.2):
+ three-stdlib@2.36.1(three@0.182.0):
dependencies:
'@types/draco3d': 1.4.10
'@types/offscreencanvas': 2019.7.3
@@ -5064,9 +5072,9 @@ snapshots:
draco3d: 1.5.7
fflate: 0.6.10
potpack: 1.0.2
- three: 0.183.2
+ three: 0.182.0
- three@0.183.2: {}
+ three@0.182.0: {}
tldts-core@6.1.86: {}
@@ -5084,25 +5092,25 @@ snapshots:
dependencies:
punycode: 2.3.1
- troika-three-text@0.52.4(three@0.183.2):
+ troika-three-text@0.52.4(three@0.182.0):
dependencies:
bidi-js: 1.0.3
- three: 0.183.2
- troika-three-utils: 0.52.4(three@0.183.2)
+ three: 0.182.0
+ troika-three-utils: 0.52.4(three@0.182.0)
troika-worker-utils: 0.52.0
webgl-sdf-generator: 1.1.1
- troika-three-utils@0.52.4(three@0.183.2):
+ troika-three-utils@0.52.4(three@0.182.0):
dependencies:
- three: 0.183.2
+ three: 0.182.0
troika-worker-utils@0.52.0: {}
- ts-jest@29.4.6(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(jest-util@30.3.0)(jest@30.3.0(@types/node@20.19.11)(ts-node@10.9.2(@types/node@20.19.11)(typescript@5.9.2)))(typescript@5.9.2):
+ ts-jest@29.4.6(@babel/core@8.0.1)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@8.0.1))(jest-util@30.3.0)(jest@30.3.0(@types/node@20.19.11)(ts-node@10.9.2(@types/node@20.19.11)(typescript@5.9.2)))(typescript@5.9.2):
dependencies:
bs-logger: 0.2.6
fast-json-stable-stringify: 2.1.0
- handlebars: 4.7.8
+ handlebars: 4.7.9
jest: 30.3.0(@types/node@20.19.11)(ts-node@10.9.2(@types/node@20.19.11)(typescript@5.9.2))
json5: 2.2.3
lodash.memoize: 4.1.2
@@ -5112,10 +5120,10 @@ snapshots:
typescript: 5.9.2
yargs-parser: 21.1.1
optionalDependencies:
- '@babel/core': 7.29.0
+ '@babel/core': 8.0.1
'@jest/transform': 30.3.0
'@jest/types': 30.3.0
- babel-jest: 30.3.0(@babel/core@7.29.0)
+ babel-jest: 30.3.0(@babel/core@8.0.1)
jest-util: 30.3.0
ts-node@10.9.2(@types/node@20.19.11)(typescript@5.9.2):
@@ -5255,7 +5263,7 @@ snapshots:
imurmurhash: 0.1.4
signal-exit: 4.1.0
- ws@8.19.0: {}
+ ws@8.21.0: {}
xml-name-validator@5.0.0: {}
@@ -5263,8 +5271,6 @@ snapshots:
y18n@5.0.8: {}
- yallist@3.1.1: {}
-
yallist@5.0.0: {}
yargs-parser@21.1.1: {}
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index 087be12..2cf77b1 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -1,15 +1,39 @@
packages:
- .
+allowBuilds:
+ '@tailwindcss/oxide': true
+ sharp: true
+ unrs-resolver: true
+
onlyBuiltDependencies:
- '@tailwindcss/oxide'
- sharp
overrides:
+ '@babel/core@<=7.29.0': '>=7.29.6'
+ brace-expansion@<1.1.13: '>=1.1.13'
+ brace-expansion@>=2.0.0 <2.0.3: '>=2.0.3'
+ handlebars@>=4.0.0 <4.7.9: '>=4.7.9'
+ handlebars@>=4.0.0 <=4.7.8: '>=4.7.9'
+ handlebars@>=4.6.0 <=4.7.8: '>=4.7.9'
+ js-yaml@<=4.1.1: '>=4.2.0'
next@>=10.0.0 <15.5.10: '>=15.5.10'
next@>=15.5.1-canary.0 <15.5.10: '>=15.5.10'
+ next@>=16.0.0 <16.2.5: '>=16.2.5'
+ next@>=16.0.0 <16.2.6: '>=16.2.6'
+ next@>=16.0.0-beta.0 <16.1.7: '>=16.1.7'
+ next@>=16.0.0-beta.0 <16.2.3: '>=16.2.3'
+ next@>=16.0.1 <16.1.7: '>=16.1.7'
+ picomatch@<2.3.2: '>=2.3.2'
+ picomatch@>=4.0.0 <4.0.4: '>=4.0.4'
+ postcss@<8.5.10: '>=8.5.10'
tar@<7.5.7: '>=7.5.7'
tar@<7.5.8: '>=7.5.8'
+ tar@<=7.5.10: '>=7.5.11'
+ tar@<=7.5.15: '>=7.5.16'
tar@<=7.5.2: '>=7.5.3'
tar@<=7.5.3: '>=7.5.4'
tar@<=7.5.9: '>=7.5.10'
+ ws@>=8.0.0 <8.20.1: '>=8.20.1'
+ ws@>=8.0.0 <8.21.0: '>=8.21.0'
diff --git a/public/edev.jpeg b/public/edev.jpeg
deleted file mode 100644
index cdb3109..0000000
Binary files a/public/edev.jpeg and /dev/null differ
diff --git a/public/edev.jpg b/public/edev.jpg
new file mode 100644
index 0000000..9679467
Binary files /dev/null and b/public/edev.jpg differ
diff --git a/public/portfolio-data.json b/public/portfolio-data.json
index f12c065..c4ff923 100644
--- a/public/portfolio-data.json
+++ b/public/portfolio-data.json
@@ -4,7 +4,7 @@
"title": "Desenvolvedor Full-Stack",
"location": "Garuva, Santa Catarina, Brasil",
"email": "evandrofonsecajunior@gmail.com",
- "phone": "+55 47 99274-2365",
+ "phone": "Disponivel pelo botao de WhatsApp",
"linkedin": "https://www.linkedin.com/in/evandro-fonseca-junior-0969aa1b0/",
"github": "https://github.com/evandrodevbr",
"summary": "Desenvolvedor Full-Stack com 3+ anos de experiência, especializado em soluções web modernas e inovadoras. Formado em Engenharia da Computação, com conhecimentos sólidos em computação em nuvem e inteligência artificial. Busco constantemente novos desafios onde possa aplicar minha paixão por tecnologia e resolver problemas de forma criativa."
@@ -367,8 +367,8 @@
},
"contact": {
"email": "evandrofonsecajunior@gmail.com",
- "phone": "+55 47 99274-2365",
- "whatsapp": "+55 47 99274-2365",
+ "phone": "Disponivel pelo botao de WhatsApp",
+ "whatsapp": "Disponivel pelo botao de WhatsApp",
"linkedin": "https://www.linkedin.com/in/evandro-fonseca-junior-0969aa1b0/",
"github": "https://github.com/evandrodevbr",
"location": "Garuva, Santa Catarina, Brasil"