diff --git a/apps/web/components/BorderBeam.tsx b/apps/web/components/BorderBeam.tsx
new file mode 100644
index 0000000..80a51d8
--- /dev/null
+++ b/apps/web/components/BorderBeam.tsx
@@ -0,0 +1,94 @@
+"use client";
+
+import { cn } from "@/lib/utils";
+import { type MotionStyle, type Transition, motion } from "motion/react";
+
+interface BorderBeamProps {
+ /**
+ * The size of the border beam.
+ */
+ size?: number;
+ /**
+ * The duration of the border beam.
+ */
+ duration?: number;
+ /**
+ * The delay of the border beam.
+ */
+ delay?: number;
+ /**
+ * The color of the border beam from.
+ */
+ colorFrom?: string;
+ /**
+ * The color of the border beam to.
+ */
+ colorTo?: string;
+ /**
+ * The motion transition of the border beam.
+ */
+ transition?: Transition;
+ /**
+ * The class name of the border beam.
+ */
+ className?: string;
+ /**
+ * The style of the border beam.
+ */
+ style?: React.CSSProperties;
+ /**
+ * Whether to reverse the animation direction.
+ */
+ reverse?: boolean;
+ /**
+ * The initial offset position (0-100).
+ */
+ initialOffset?: number;
+}
+
+export const BorderBeam = ({
+ className,
+ size = 50,
+ delay = 0,
+ duration = 6,
+ colorFrom = "#ffaa40",
+ colorTo = "#9c40ff",
+ transition,
+ style,
+ reverse = false,
+ initialOffset = 0,
+}: BorderBeamProps) => {
+ return (
+
+
+
+ );
+};
diff --git a/apps/web/package.json b/apps/web/package.json
index bc861b3..138ab73 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -10,6 +10,8 @@
"postinstall": "fumadocs-mdx"
},
"dependencies": {
+ "@xyflow/react": "^12.4.3",
+ "framer-motion": "^12.4.3",
"fumadocs-core": "15.0.6",
"fumadocs-mdx": "11.5.3",
"fumadocs-ui": "15.0.6",
diff --git a/apps/web/src/app/(home)/_components/CustomizableSection.tsx b/apps/web/src/app/(home)/_components/CustomizableSection.tsx
new file mode 100644
index 0000000..765ce44
--- /dev/null
+++ b/apps/web/src/app/(home)/_components/CustomizableSection.tsx
@@ -0,0 +1,60 @@
+import { motion } from "framer-motion";
+import CustomizableStack from "./CustomizableStack";
+
+export default function CustomizableSection() {
+ return (
+
+
+
+ Your Stack, Your Choice
+
+
+
+ Better-T Stack comes with carefully selected defaults, but we
+ understand one size doesn't fit all.
+
+ {" "}
+ Customize your stack{" "}
+
+ while maintaining full type safety and integration.
+
+
+
+
+ Multiple Database Options
+
+
+ Flexible Authentication
+
+
+ Alternative ORMs
+
+
+ Framework Choices
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/web/src/app/(home)/_components/CustomizableStack.tsx b/apps/web/src/app/(home)/_components/CustomizableStack.tsx
new file mode 100644
index 0000000..5ac5993
--- /dev/null
+++ b/apps/web/src/app/(home)/_components/CustomizableStack.tsx
@@ -0,0 +1,177 @@
+"use client";
+
+import {
+ Background,
+ type Connection,
+ type Edge,
+ ReactFlow,
+ useEdgesState,
+ useNodesState,
+} from "@xyflow/react";
+import { useCallback, useState } from "react";
+import { TechSelector } from "./TechSelector";
+import "@xyflow/react/dist/style.css";
+import { initialNodes } from "@/lib/constant";
+import { TechNodeComponent } from "./TechNodeComponent";
+
+const initialEdges = [
+ { id: "bun-hono", source: "bun", target: "hono", animated: true },
+ { id: "bun-tanstack", source: "bun", target: "tanstack", animated: true },
+ { id: "hono-libsql", source: "hono", target: "libsql", animated: true },
+ { id: "libsql-drizzle", source: "libsql", target: "drizzle", animated: true },
+ {
+ id: "hono-better-auth",
+ source: "hono",
+ target: "better-auth",
+ animated: true,
+ },
+ { id: "bun-tailwind", source: "bun", target: "tailwind", animated: true },
+ {
+ id: "tailwind-shadcn",
+ source: "tailwind",
+ target: "shadcn",
+ animated: true,
+ },
+];
+
+const nodeTypes = {
+ techNode: TechNodeComponent,
+};
+
+const CustomizableStack = () => {
+ const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
+ const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
+ const [activeNodes, setActiveNodes] = useState({
+ backend: "hono",
+ database: "libsql",
+ orm: "drizzle",
+ auth: "better-auth",
+ });
+
+ const handleTechSelect = useCallback(
+ (category: string, techId: string) => {
+ setActiveNodes((prev) => ({ ...prev, [category]: techId }));
+
+ setNodes((nds) =>
+ nds.map((node) => ({
+ ...node,
+ data: {
+ ...node.data,
+ isActive: node.data.isStatic
+ ? true
+ : node.data.category === category
+ ? node.id === techId
+ : node.data.isActive,
+ },
+ })),
+ );
+
+ const sourceNodes = nodes.filter(
+ (n) => n.data.isActive && !n.data.isStatic,
+ );
+ const targetNode = nodes.find((n) => n.id === techId);
+
+ if (!targetNode) return;
+
+ setEdges((eds) =>
+ eds.filter(
+ (edge) =>
+ !nodes.some(
+ (n) =>
+ n.data.category === category &&
+ (edge.source === n.id || edge.target === n.id),
+ ),
+ ),
+ );
+
+ setEdges((eds) => [
+ ...eds,
+ ...sourceNodes.map((source) => ({
+ id: `${source.id}-${techId}`,
+ source: source.id,
+ target: techId,
+ animated: true,
+ })),
+ ]);
+ },
+ [nodes, setNodes, setEdges],
+ );
+
+ const onConnect = useCallback(
+ (connection: Connection) => {
+ const sourceNode = nodes.find((n) => n.id === connection.source);
+ const targetNode = nodes.find((n) => n.id === connection.target);
+
+ if (!sourceNode || !targetNode) return;
+
+ if (sourceNode.data.group === targetNode.data.group) {
+ return;
+ }
+
+ const edgesToRemove = edges.filter((edge) => {
+ const edgeTarget = nodes.find((n) => n.id === edge.target);
+ return edgeTarget?.data.group === targetNode.data.group;
+ });
+
+ setEdges((eds) => {
+ const newEdges = eds.filter((edge) => !edgesToRemove.includes(edge));
+ return [...newEdges, { ...(connection as Edge), animated: true }];
+ });
+
+ setNodes((nds) =>
+ nds.map((node) => ({
+ ...node,
+ data: {
+ ...node.data,
+ isActive:
+ node.id === connection.source || node.id === connection.target
+ ? true
+ : node.data.group !== targetNode.data.group
+ ? node.data.isActive
+ : false,
+ },
+ })),
+ );
+ },
+ [nodes, edges, setEdges, setNodes],
+ );
+
+ return (
+
+
+
+
+ Select technologies from the left panel to customize your stack. The
+ graph will automatically update connections.
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default CustomizableStack;
diff --git a/apps/web/src/app/(home)/_components/Navbar.tsx b/apps/web/src/app/(home)/_components/Navbar.tsx
index e3e59d6..b643894 100644
--- a/apps/web/src/app/(home)/_components/Navbar.tsx
+++ b/apps/web/src/app/(home)/_components/Navbar.tsx
@@ -56,7 +56,7 @@ const Navbar = () => {
{
style={{
transform: scrolled ? "translateY(0)" : "translateY(-8px)",
}}
- className={`text-gray-300 hover:text-white transition-all duration-300 py-2 px-4 rounded-full ${
+ className={`text-violet-700 hover:text-white transition-all duration-300 py-2 px-4 rounded-full ${
scrolled
? "opacity-100 translate-y-0"
: "opacity-0 pointer-events-none"
diff --git a/apps/web/src/app/(home)/_components/SideCircles.tsx b/apps/web/src/app/(home)/_components/SideCircles.tsx
index 1db09ef..2dec64e 100644
--- a/apps/web/src/app/(home)/_components/SideCircles.tsx
+++ b/apps/web/src/app/(home)/_components/SideCircles.tsx
@@ -2,14 +2,14 @@ const SideCircles = () => {
return (
<>
>
);
diff --git a/apps/web/src/app/(home)/_components/TechConstellation.tsx b/apps/web/src/app/(home)/_components/TechConstellation.tsx
index 63dddae..4254a79 100644
--- a/apps/web/src/app/(home)/_components/TechConstellation.tsx
+++ b/apps/web/src/app/(home)/_components/TechConstellation.tsx
@@ -153,7 +153,7 @@ const TechConstellation = () => {
return (
+
+
+
+
+ {data.label}
+
+
+ {data.description}
+
+ {!data.isDefault && !data.isStatic && (
+
+ Alternative Option
+
+ )}
+
+
+
+
+ );
+}
diff --git a/apps/web/src/app/(home)/_components/TechSelector.tsx b/apps/web/src/app/(home)/_components/TechSelector.tsx
new file mode 100644
index 0000000..a0a0040
--- /dev/null
+++ b/apps/web/src/app/(home)/_components/TechSelector.tsx
@@ -0,0 +1,81 @@
+type TechOption = {
+ id: string;
+ label: string;
+ category: string;
+};
+
+const techOptions: Record
= {
+ backend: [
+ { id: "hono", label: "Hono", category: "backend" },
+ { id: "express", label: "Express", category: "backend" },
+ ],
+ database: [
+ { id: "libsql", label: "libSQL", category: "database" },
+ { id: "postgres", label: "PostgreSQL", category: "database" },
+ ],
+ orm: [
+ { id: "drizzle", label: "Drizzle", category: "orm" },
+ { id: "prisma", label: "Prisma", category: "orm" },
+ ],
+ auth: [
+ { id: "better-auth", label: "Better-Auth", category: "auth" },
+ { id: "no-auth", label: "No Auth", category: "auth" },
+ ],
+};
+
+interface TechSelectorProps {
+ onSelect: (category: string, techId: string) => void;
+ activeNodes: Record;
+}
+
+export function TechSelector({ onSelect, activeNodes }: TechSelectorProps) {
+ return (
+
+
Customize Stack
+ {Object.entries(techOptions).map(([category, options]) => (
+
+
{category}
+
+ {options.map((option) => (
+ onSelect(category, option.id)}
+ >
+ {option.label}
+
+ ))}
+
+
+ ))}
+
+ );
+}
+
+const Badge = ({
+ children,
+ className,
+ ...props
+}: {
+ children: React.ReactNode;
+ variant: "primary" | "secondary";
+ className?: string;
+ onClick?: () => void;
+}) => {
+ return (
+
+ {children}
+
+ );
+};
diff --git a/apps/web/src/app/(home)/page.tsx b/apps/web/src/app/(home)/page.tsx
index 80d5c39..0bb0141 100644
--- a/apps/web/src/app/(home)/page.tsx
+++ b/apps/web/src/app/(home)/page.tsx
@@ -4,7 +4,8 @@ import { Poppins } from "next/font/google";
import React from "react";
import BackgroundGradients from "./_components/BackgroundGradients";
import CodeContainer from "./_components/CodeContainer";
-import Featured from "./_components/FeaturedSection";
+import CustomizableSection from "./_components/CustomizableSection";
+// import Featured from "./_components/FeaturedSection";
import NpmPackage from "./_components/NpmPackage";
import SideCircles from "./_components/SideCircles";
import Spotlight from "./_components/Spotlight";
@@ -62,6 +63,7 @@ export default function HomePage() {
+
@@ -90,9 +92,9 @@ export default function HomePage() {
-
-
+
+
);
}
diff --git a/apps/web/src/app/global.css b/apps/web/src/app/global.css
index 3cc1174..1e81c16 100644
--- a/apps/web/src/app/global.css
+++ b/apps/web/src/app/global.css
@@ -52,3 +52,16 @@
opacity: 0;
animation: fadeInUp 0.5s ease-out forwards;
}
+
+.border-beam {
+ animation: border-beam 3s linear infinite;
+}
+
+@keyframes border-beam {
+ 0% {
+ background-position: 0% 50%;
+ }
+ 100% {
+ background-position: 200% 50%;
+ }
+}
diff --git a/apps/web/src/lib/constant.ts b/apps/web/src/lib/constant.ts
index 0c330eb..f929674 100644
--- a/apps/web/src/lib/constant.ts
+++ b/apps/web/src/lib/constant.ts
@@ -9,6 +9,7 @@ import {
ServerCog,
Workflow,
} from "lucide-react";
+import type { TechNode } from "./types";
export const technologies = [
{
@@ -103,3 +104,161 @@ export const technologies = [
left: "left-[6rem]",
},
];
+
+export const initialNodes: TechNode[] = [
+ {
+ id: "bun",
+ type: "techNode",
+ position: { x: 536, y: 204 },
+ data: {
+ label: "Bun",
+ category: "core",
+ description: "Fast all-in-one JavaScript runtime",
+ isDefault: true,
+ isActive: true,
+ },
+ },
+ {
+ id: "tanstack",
+ type: "techNode",
+ position: { x: 362, y: 296 },
+ data: {
+ label: "TanStack Router",
+ category: "frontend",
+ description: "Type-safe routing",
+ isDefault: true,
+ isActive: true,
+ group: "router",
+ },
+ },
+ {
+ id: "tailwind",
+ type: "techNode",
+ position: { x: 494, y: 379 },
+ data: {
+ label: "Tailwind CSS",
+ category: "frontend",
+ description: "Utility-first CSS framework",
+ isDefault: true,
+ isActive: true,
+ isStatic: true,
+ },
+ },
+ {
+ id: "shadcn",
+ type: "techNode",
+ position: { x: 358, y: 486 },
+ data: {
+ label: "shadcn/ui",
+ category: "frontend",
+ description: "Re-usable components",
+ isDefault: true,
+ isActive: true,
+ isStatic: true,
+ },
+ },
+ {
+ id: "hono",
+ type: "techNode",
+ position: { x: 700, y: 325 },
+ data: {
+ label: "Hono",
+ category: "backend",
+ description: "Ultrafast web framework",
+ isDefault: true,
+ isActive: true,
+ group: "backend",
+ },
+ },
+ {
+ id: "express",
+ type: "techNode",
+ position: { x: 897, y: 389 },
+ data: {
+ label: "Express",
+ category: "backend",
+ description: "Fast, unopinionated web framework",
+ isDefault: false,
+ isActive: false,
+ group: "backend",
+ },
+ },
+ {
+ id: "libsql",
+ type: "techNode",
+ position: { x: 544, y: 532 },
+ data: {
+ label: "libSQL",
+ category: "database",
+ description: "SQLite-compatible database",
+ isDefault: true,
+ isActive: true,
+ group: "database",
+ },
+ },
+ {
+ id: "postgres",
+ type: "techNode",
+ position: { x: 318, y: 579 },
+ data: {
+ label: "PostgreSQL",
+ category: "database",
+ description: "Advanced SQL database",
+ isDefault: false,
+ isActive: false,
+ group: "database",
+ },
+ },
+ {
+ id: "drizzle",
+ type: "techNode",
+ position: { x: 559, y: 651 },
+ data: {
+ label: "Drizzle",
+ category: "orm",
+ description: "TypeScript ORM",
+ isDefault: true,
+ isActive: true,
+ group: "orm",
+ },
+ },
+ {
+ id: "prisma",
+ type: "techNode",
+ position: { x: 707, y: 675 },
+ data: {
+ label: "Prisma",
+ category: "orm",
+ description: "Next-generation ORM",
+ isDefault: false,
+ isActive: false,
+ group: "orm",
+ },
+ },
+ {
+ id: "better-auth",
+ type: "techNode",
+ position: { x: 770, y: 502 },
+ data: {
+ label: "Better-Auth",
+ category: "auth",
+ description: "Modern authentication",
+ isDefault: true,
+ isActive: true,
+ group: "auth",
+ },
+ },
+ {
+ id: "no-auth",
+ type: "techNode",
+ position: { x: 950, y: 621 },
+ data: {
+ label: "No Auth",
+ category: "auth",
+ description: "No authentication needed",
+ isDefault: false,
+ isActive: false,
+ group: "auth",
+ },
+ },
+];
diff --git a/apps/web/src/lib/types.ts b/apps/web/src/lib/types.ts
new file mode 100644
index 0000000..27650f2
--- /dev/null
+++ b/apps/web/src/lib/types.ts
@@ -0,0 +1,32 @@
+export type TechCategory =
+ | "core"
+ | "frontend"
+ | "backend"
+ | "database"
+ | "auth"
+ | "orm"
+ | "router";
+
+export interface TechNode {
+ id: string;
+ type: string;
+ position: { x: number; y: number };
+ data: {
+ label: string;
+ category: TechCategory;
+ description: string;
+ isDefault: boolean;
+ alternatives?: string[];
+ isActive: boolean;
+ group?: TechCategory;
+ isStatic?: boolean;
+ };
+}
+
+export interface TechEdge {
+ id: string;
+ source: string;
+ target: string;
+ type?: string;
+ animated?: boolean;
+}
diff --git a/bun.lock b/bun.lock
index 1e45b0f..032bddf 100644
--- a/bun.lock
+++ b/bun.lock
@@ -39,6 +39,8 @@
"name": "web",
"version": "0.0.0",
"dependencies": {
+ "@xyflow/react": "^12.4.3",
+ "framer-motion": "^12.4.3",
"fumadocs-core": "15.0.6",
"fumadocs-mdx": "11.5.3",
"fumadocs-ui": "15.0.6",
@@ -448,6 +450,18 @@
"@types/acorn": ["@types/acorn@4.0.6", "", { "dependencies": { "@types/estree": "*" } }, "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ=="],
+ "@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="],
+
+ "@types/d3-drag": ["@types/d3-drag@3.0.7", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ=="],
+
+ "@types/d3-interpolate": ["@types/d3-interpolate@3.0.4", "", { "dependencies": { "@types/d3-color": "*" } }, "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA=="],
+
+ "@types/d3-selection": ["@types/d3-selection@3.0.11", "", {}, "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w=="],
+
+ "@types/d3-transition": ["@types/d3-transition@3.0.9", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg=="],
+
+ "@types/d3-zoom": ["@types/d3-zoom@3.0.8", "", { "dependencies": { "@types/d3-interpolate": "*", "@types/d3-selection": "*" } }, "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw=="],
+
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
"@types/degit": ["@types/degit@2.8.6", "", {}, "sha512-y0M7sqzsnHB6cvAeTCBPrCQNQiZe8U4qdzf8uBVmOWYap5MMTN/gB2iEqrIqFiYcsyvP74GnGD5tgsHttielFw=="],
@@ -498,6 +512,10 @@
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="],
+ "@xyflow/react": ["@xyflow/react@12.4.3", "", { "dependencies": { "@xyflow/system": "0.0.51", "classcat": "^5.0.3", "zustand": "^4.4.0" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "sha512-oO50TIY4rbgOURK5pmvL4LwLOQdh6YkvrvOBZPBedltJ1TINCRp0FiyYKfYhLnaDcW8/aayvGtFpUcSkPQxpGg=="],
+
+ "@xyflow/system": ["@xyflow/system@0.0.51", "", { "dependencies": { "@types/d3-drag": "^3.0.7", "@types/d3-selection": "^3.0.10", "@types/d3-transition": "^3.0.8", "@types/d3-zoom": "^3.0.8", "d3-drag": "^3.0.0", "d3-selection": "^3.0.0", "d3-zoom": "^3.0.0" } }, "sha512-cYnuM3oWQQjx2Rdz0LdZCnbUaWZdZDiik20kPDYsa5SIlq++ZDIcKiDF6a93ncfMv9Ej5GWfDkouE7bObrdRqQ=="],
+
"acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="],
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
@@ -596,6 +614,8 @@
"class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="],
+ "classcat": ["classcat@5.0.5", "", {}, "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w=="],
+
"cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="],
"cli-truncate": ["cli-truncate@4.0.0", "", { "dependencies": { "slice-ansi": "^5.0.0", "string-width": "^7.0.0" } }, "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA=="],
@@ -634,6 +654,24 @@
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
+ "d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="],
+
+ "d3-dispatch": ["d3-dispatch@3.0.1", "", {}, "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg=="],
+
+ "d3-drag": ["d3-drag@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-selection": "3" } }, "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg=="],
+
+ "d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="],
+
+ "d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "1 - 3" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="],
+
+ "d3-selection": ["d3-selection@3.0.0", "", {}, "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ=="],
+
+ "d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="],
+
+ "d3-transition": ["d3-transition@3.0.1", "", { "dependencies": { "d3-color": "1 - 3", "d3-dispatch": "1 - 3", "d3-ease": "1 - 3", "d3-interpolate": "1 - 3", "d3-timer": "1 - 3" }, "peerDependencies": { "d3-selection": "2 - 3" } }, "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w=="],
+
+ "d3-zoom": ["d3-zoom@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", "d3-interpolate": "1 - 3", "d3-selection": "2 - 3", "d3-transition": "2 - 3" } }, "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw=="],
+
"damerau-levenshtein": ["damerau-levenshtein@1.0.8", "", {}, "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="],
"data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="],
@@ -794,6 +832,8 @@
"foreground-child": ["foreground-child@3.3.0", "", { "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" } }, "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg=="],
+ "framer-motion": ["framer-motion@12.4.3", "", { "dependencies": { "motion-dom": "^12.0.0", "motion-utils": "^12.0.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-rsMeO7w3dKyNG09o3cGwSH49iHU+VgDmfSSfsX+wfkO3zDA6WWkh4sUsMXd155YROjZP+7FTIhDrBYfgZeHjKQ=="],
+
"fs-extra": ["fs-extra@11.3.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew=="],
"fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="],
@@ -1184,6 +1224,10 @@
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
+ "motion-dom": ["motion-dom@12.0.0", "", { "dependencies": { "motion-utils": "^12.0.0" } }, "sha512-CvYd15OeIR6kHgMdonCc1ihsaUG4MYh/wrkz8gZ3hBX/uamyZCXN9S9qJoYF03GqfTt7thTV/dxnHYX4+55vDg=="],
+
+ "motion-utils": ["motion-utils@12.0.0", "", {}, "sha512-MNFiBKbbqnmvOjkPyOKgHUp3Q6oiokLkI1bEwm5QA28cxMZrv0CbbBGDNmhF6DIXsi1pCQBSs0dX8xjeER1tmA=="],
+
"mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
@@ -1566,6 +1610,8 @@
"use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="],
+ "use-sync-external-store": ["use-sync-external-store@1.4.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw=="],
+
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
"vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
@@ -1602,6 +1648,8 @@
"zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="],
+ "zustand": ["zustand@4.5.6", "", { "dependencies": { "use-sync-external-store": "^1.2.2" }, "peerDependencies": { "@types/react": ">=16.8", "immer": ">=9.0.6", "react": ">=16.8" }, "optionalPeers": ["@types/react", "immer", "react"] }, "sha512-ibr/n1hBzLLj5Y+yUcU7dYw8p6WnIVzdJbnX+1YpaScvZVF2ziugqHs+LAmHw4lWO9c/zRj+K1ncgWDQuthEdQ=="],
+
"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
"@changesets/apply-release-plan/fs-extra": ["fs-extra@7.0.1", "", { "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw=="],