From 1a345086998600bb0b4b7408705cd1a61123cb81 Mon Sep 17 00:00:00 2001 From: sasha-astiadi Date: Mon, 17 Nov 2025 15:12:55 +0100 Subject: [PATCH] refactor: rename and update pod animations with improved visuals and consistency - Renamed NoCentral to DataControl with enhanced data ownership visualization - Renamed NoExtraction to Connectivity with full mesh P2P topology - Renamed NoSinglePoint to Security with improved styling - Renamed NoControl to Resilience with consistent styling - Added lg:-mt-12 margin to Security and Resilience animations for alignment - Updated DataControl to show explicit permission gates and bi-directional replication --- src/pages/pods/PodsBento.tsx | 16 +- src/pages/pods/animations/Connectivity.tsx | 176 ++++++++++++++ src/pages/pods/animations/DataControl.tsx | 239 ++++++++++++++++++ src/pages/pods/animations/NoCentral.tsx | 238 ------------------ src/pages/pods/animations/NoControl.tsx | 175 -------------- src/pages/pods/animations/NoExtraction.tsx | 247 ------------------- src/pages/pods/animations/NoSinglePoint.tsx | 225 ----------------- src/pages/pods/animations/Resilience.tsx | 255 ++++++++++++++++++++ src/pages/pods/animations/Security.tsx | 231 ++++++++++++++++++ 9 files changed, 909 insertions(+), 893 deletions(-) create mode 100644 src/pages/pods/animations/Connectivity.tsx create mode 100644 src/pages/pods/animations/DataControl.tsx delete mode 100644 src/pages/pods/animations/NoCentral.tsx delete mode 100644 src/pages/pods/animations/NoControl.tsx delete mode 100644 src/pages/pods/animations/NoExtraction.tsx delete mode 100644 src/pages/pods/animations/NoSinglePoint.tsx create mode 100644 src/pages/pods/animations/Resilience.tsx create mode 100644 src/pages/pods/animations/Security.tsx diff --git a/src/pages/pods/PodsBento.tsx b/src/pages/pods/PodsBento.tsx index ebdeb65..bb42f49 100644 --- a/src/pages/pods/PodsBento.tsx +++ b/src/pages/pods/PodsBento.tsx @@ -1,10 +1,10 @@ "use client"; import { Eyebrow, H3, P } from "@/components/Texts"; -import NoExtraction from "./animations/NoExtraction"; -import NoControl from "./animations/NoControl"; -import NoCentral from "./animations/NoCentral"; -import NoSinglePoint from "./animations/NoSinglePoint"; +import DataControl from "./animations/DataControl"; +import Connectivity from "./animations/Connectivity"; +import Security from "./animations/Security"; +import Resilience from "./animations/Resilience"; const deterministicCards = [ { @@ -26,7 +26,7 @@ const deterministicCards = [ title: "Your Data Lives on Your Pods", description: "Full control of where your data is stored and how it’s shared.", - animation: , + animation: , colSpan: "lg:col-span-3", rowSpan: "lg:row-span-1", rounded: "lg:rounded-tr-4xl max-lg:rounded-t-4xl", @@ -40,7 +40,7 @@ const deterministicCards = [ title: "Direct Pod-to-Pod Networking", description: "Direct connections between Pods for faster, private communication.", - animation: , + animation: , colSpan: "lg:col-span-2", rowSpan: "lg:row-span-1", rounded: "lg:rounded-bl-4xl max-lg:rounded-b-4xl", @@ -54,7 +54,7 @@ const deterministicCards = [ title: "No One Can Spy or Shut You Down", description: "Independence from corporate servers or cloud outages.", - animation: , + animation: , colSpan: "lg:col-span-2", rowSpan: "lg:row-span-1", rounded: "", @@ -67,7 +67,7 @@ const deterministicCards = [ title: "Resilient Even if Nodes Disconnect", description: "Continuous availability even if one node disconnects.", - animation: , + animation: , colSpan: "lg:col-span-2", rowSpan: "lg:row-span-1", rounded: "lg:rounded-br-4xl max-lg:rounded-b-4xl", diff --git a/src/pages/pods/animations/Connectivity.tsx b/src/pages/pods/animations/Connectivity.tsx new file mode 100644 index 0000000..8723156 --- /dev/null +++ b/src/pages/pods/animations/Connectivity.tsx @@ -0,0 +1,176 @@ +"use client"; + +import { motion, useReducedMotion } from "framer-motion"; +import clsx from "clsx"; + +type Props = { + className?: string; + accent?: string; + bg?: string; + gridStroke?: string; +}; + +const W = 720; // 4:3 width +const H = 540; // 4:3 height + +export default function Connectivity({ + className, + accent = "#00b8db", + bg = "#0b0b0b", + gridStroke = "#2b2a2a", +}: Props) { + const prefers = useReducedMotion(); + + // Hex-like P2P topology — all peers connect *directly* + const pods = [ + { x: 250, y: 160 }, + { x: 470, y: 160 }, + { x: 580, y: 290 }, + { x: 470, y: 420 }, + { x: 250, y: 420 }, + { x: 140, y: 290 }, + ]; + + // Every pod connects to every other pod = full direct mesh + const links: [number, number][] = []; + for (let i = 0; i < pods.length; i++) { + for (let j = i + 1; j < pods.length; j++) links.push([i, j]); + } + + const line = (i: number, j: number) => { + const a = pods[i], b = pods[j]; + return `M ${a.x} ${a.y} L ${b.x} ${b.y}`; + }; + + return ( +
+ + + {/* ========= GRID + FILTERS ========= */} + + + + + + + + + + + + + + {/* Cyan soft gradient for pods */} + + + + + + + + + {/* ========= BASE CONNECTION LINES (Full Mesh) ========= */} + {links.map(([i, j], idx) => ( + + ))} + + {/* ========= ACCENT DASH (Active P2P links) ========= */} + {links.map(([i, j], idx) => ( + + ))} + + {/* ========= MOVING SIGNALS (Direct P2P) ========= */} + {!prefers && + links.map(([i, j], idx) => ( + + ))} + + {/* ========= CLOUD PODS ========= */} + {pods.map((p, i) => ( + + {/* Outer soft cyan aura */} + {!prefers && ( + + )} + + {/* Pod body */} + + + {/* Inner dark core */} + + + ))} + +
+ ); +} diff --git a/src/pages/pods/animations/DataControl.tsx b/src/pages/pods/animations/DataControl.tsx new file mode 100644 index 0000000..d3b4c85 --- /dev/null +++ b/src/pages/pods/animations/DataControl.tsx @@ -0,0 +1,239 @@ +"use client"; + +import { motion, useReducedMotion } from "framer-motion"; +import clsx from "clsx"; + +type Props = { + className?: string; + accent?: string; // cyan + bg?: string; // solid dark + gridStroke?: string; // grid color +}; + +const W = 720; // 4:3 +const H = 540; // 4:3 + +export default function DataControl({ + className, + accent = "#00b8db", + bg = "#0b0b0b", + gridStroke = "#2b2a2a", +}: Props) { + const prefers = useReducedMotion(); + + // Central "Your Pod" + const center = { x: W / 2, y: H / 2 + 10 }; + + // Personal pods (owned) — left-bottom cluster + const owned = [ + { x: 200, y: 380 }, + { x: 260, y: 320 }, + { x: 140, y: 320 }, + ]; + + // External peers (share targets) — top-right cluster + const peers = [ + { x: 520, y: 180 }, + { x: 600, y: 140 }, + { x: 580, y: 240 }, + ]; + + // helper + const line = (a: {x:number;y:number}, b:{x:number;y:number}) => `M ${a.x} ${a.y} L ${b.x} ${b.y}`; + + // "Gates" sit near the center to symbolize explicit permission before data leaves your pod + const gates = peers.map((p, i) => { + // point 30% of the way from center to peer + const gx = center.x + (p.x - center.x) * 0.28; + const gy = center.y + (p.y - center.y) * 0.28; + return { x: gx, y: gy }; + }); + + // Paths for outbound shares (center -> gate -> peer) + const sharePaths = peers.map((p, i) => + `M ${center.x} ${center.y} L ${gates[i].x} ${gates[i].y} L ${p.x} ${p.y}` + ); + + // Paths for local replication (center <-> owned pods) + const localPaths = owned.map((o) => line(center, o)); + + return ( + + ); +} diff --git a/src/pages/pods/animations/NoCentral.tsx b/src/pages/pods/animations/NoCentral.tsx deleted file mode 100644 index d5220f6..0000000 --- a/src/pages/pods/animations/NoCentral.tsx +++ /dev/null @@ -1,238 +0,0 @@ -"use client"; - -import { motion, useReducedMotion } from "framer-motion"; -import clsx from "clsx"; - -type Props = { - className?: string; - accent?: string; - bg?: string; -}; - -const W = 760; -const H = 420; - -const Node = ({ - x, - y, - r = 10, - accent = "#00b8db", - pulse = false, - delay = 0, -}: { - x: number; - y: number; - r?: number; - accent?: string; - pulse?: boolean; - delay?: number; -}) => { - const prefers = useReducedMotion(); - return ( - <> - - - - ); -}; - -const Packet = ({ - path, - delay = 0, - accent = "#00b8db", - duration = 2.4, -}: { - path: string; - delay?: number; - accent?: string; - duration?: number; -}) => { - const prefers = useReducedMotion(); - return ( - - ); -}; - -export default function NoCentral({ - className, - accent = "#00b8db", - bg = "#0a0a0a", -}: Props) { - const center = { x: 380, y: 210 }; - const nodes = [ - { x: 160, y: 100 }, - { x: 270, y: 70 }, - { x: 500, y: 90 }, - { x: 620, y: 150 }, - { x: 220, y: 300 }, - { x: 360, y: 340 }, - { x: 530, y: 290 }, - ]; - - const links = [ - [nodes[0], nodes[1]], - [nodes[1], nodes[2]], - [nodes[2], nodes[3]], - [nodes[0], nodes[4]], - [nodes[4], nodes[5]], - [nodes[5], nodes[6]], - [nodes[1], nodes[5]], - [nodes[3], nodes[6]], - ]; - - return ( - - ); -} diff --git a/src/pages/pods/animations/NoControl.tsx b/src/pages/pods/animations/NoControl.tsx deleted file mode 100644 index 17d3be5..0000000 --- a/src/pages/pods/animations/NoControl.tsx +++ /dev/null @@ -1,175 +0,0 @@ -"use client"; - -import { motion, useReducedMotion } from "framer-motion"; -import clsx from "clsx"; - -type Props = { - className?: string; - accent?: string; - bg?: string; -}; - -const W = 760; -const H = 420; - -/** Node component */ -const Node = ({ - x, - y, - r = 14, - accent = "#00b8db", - pulse = false, - faded = false, -}: { - x: number; - y: number; - r?: number; - accent?: string; - pulse?: boolean; - faded?: boolean; -}) => { - const prefers = useReducedMotion(); - return ( - <> - - - - ); -}; - -/** Moving packet along a path */ -const Packet = ({ - path, - delay = 0, - accent = "#00b8db", -}: { - path: string; - delay?: number; - accent?: string; -}) => { - const prefers = useReducedMotion(); - return ( - - ); -}; - -export default function NoControl({ - className, - accent = "#00b8db", - bg = "#0a0a0a", -}: Props) { - const center = { x: 380, y: 210 }; - const outer = [ - { x: 160, y: 120 }, - { x: 600, y: 120 }, - { x: 160, y: 300 }, - { x: 600, y: 300 }, - ]; - - const link = (a: any, b: any) => `M ${a.x} ${a.y} L ${b.x} ${b.y}`; - - return ( - - ); -} diff --git a/src/pages/pods/animations/NoExtraction.tsx b/src/pages/pods/animations/NoExtraction.tsx deleted file mode 100644 index 52c044b..0000000 --- a/src/pages/pods/animations/NoExtraction.tsx +++ /dev/null @@ -1,247 +0,0 @@ -"use client"; - -import { motion, useReducedMotion } from "framer-motion"; -import clsx from "clsx"; - -type Props = { - className?: string; - accent?: string; - bg?: string; -}; - -const W = 760; -const H = 420; - -/** Node = local data cluster */ -const Node = ({ - x, - y, - r = 10, - accent = "#00b8db", - pulse = false, - delay = 0, -}: { - x: number; - y: number; - r?: number; - accent?: string; - pulse?: boolean; - delay?: number; -}) => { - const prefers = useReducedMotion(); - return ( - <> - {/* outer glow */} - - {/* data core */} - - - ); -}; - -/** A data particle traveling along a given path */ -const Particle = ({ - path, - delay = 0, - accent = "#00b8db", - duration = 2, - reverse = false, -}: { - path: string; - delay?: number; - accent?: string; - duration?: number; - reverse?: boolean; -}) => { - const prefers = useReducedMotion(); - return ( - - ); -}; - -export default function NoExtraction({ - className, - accent = "#00b8db", - bg = "#0a0a0a", -}: Props) { - const center = { x: 380, y: 210 }; - const WBOX = 360; - const HBOX = 220; - const boxX = center.x - WBOX / 2; - const boxY = center.y - HBOX / 2; - - // local nodes within boundary - const nodes = [ - { x: center.x - 80, y: center.y - 40 }, - { x: center.x + 60, y: center.y - 50 }, - { x: center.x, y: center.y + 50 }, - { x: center.x - 50, y: center.y + 30 }, - ]; - - // internal circulation paths - const internalPaths = [ - `M ${center.x - 80} ${center.y - 40} Q ${center.x} ${center.y - 80} ${center.x + 60} ${center.y - 50}`, - `M ${center.x - 50} ${center.y + 30} Q ${center.x} ${center.y + 70} ${center.x} ${center.y + 50}`, - ]; - - // escape attempt path - const attemptPath = `M ${center.x} ${center.y} Q ${center.x + 200} ${center.y - 50} ${center.x + 130} ${center.y}`; - - return ( - - ); -} diff --git a/src/pages/pods/animations/NoSinglePoint.tsx b/src/pages/pods/animations/NoSinglePoint.tsx deleted file mode 100644 index 8d16498..0000000 --- a/src/pages/pods/animations/NoSinglePoint.tsx +++ /dev/null @@ -1,225 +0,0 @@ -"use client"; - -import { motion, useReducedMotion } from "framer-motion"; -import clsx from "clsx"; - -type Props = { - className?: string; - accent?: string; // cyan - bg?: string; // solid dark background - gridStroke?: string; -}; - -const W = 720; // 4:3 -const H = 540; // 4:3 - -export default function NoSinglePoint({ - className, - accent = "#00b8db", - bg = "#0b0b0b", - gridStroke = "#2b2a2a", -}: Props) { - const prefers = useReducedMotion(); - - // Nodes (left source, right dest, top hub, bottom hub, plus two relays) - const nodes = { - left: { x: 120, y: H / 2 }, - right: { x: W - 120, y: H / 2 }, - top: { x: W / 2, y: 160 }, - bot: { x: W / 2, y: H - 160 }, - tl: { x: 240, y: 200 }, - br: { x: W - 240, y: H - 200 }, - }; - - // Redundant paths from left → right - const upperPath = `M ${nodes.left.x} ${nodes.left.y} - L ${nodes.tl.x} ${nodes.tl.y} - L ${nodes.top.x} ${nodes.top.y} - L ${nodes.right.x} ${nodes.right.y}`; - - const lowerPath = `M ${nodes.left.x} ${nodes.left.y} - L ${nodes.bot.x} ${nodes.bot.y} - L ${nodes.br.x} ${nodes.br.y} - L ${nodes.right.x} ${nodes.right.y}`; - - return ( - - ); -} diff --git a/src/pages/pods/animations/Resilience.tsx b/src/pages/pods/animations/Resilience.tsx new file mode 100644 index 0000000..68b9adc --- /dev/null +++ b/src/pages/pods/animations/Resilience.tsx @@ -0,0 +1,255 @@ +"use client"; + +import { motion, useReducedMotion } from "framer-motion"; +import clsx from "clsx"; + +type Props = { + className?: string; + accent?: string; // cyan + danger?: string; // failing node color + bg?: string; // dark background + gridStroke?: string; // grid +}; + +const W = 720; +const H = 540; + +export default function Resilience({ + className, + accent = "#00b8db", + danger = "#ff4d4d", + bg = "#0b0b0b", + gridStroke = "#2b2a2a", +}: Props) { + const prefers = useReducedMotion(); + + // Primary healthy nodes + const nodes = [ + { x: 220, y: 180 }, + { x: 500, y: 180 }, + { x: 580, y: 330 }, + { x: 360, y: 420 }, + { x: 160, y: 330 }, + ]; + + // One failing node + const failing = { x: 360, y: 100 }; + + // Full mesh except failing node + const links: [number, number][] = []; + for (let i = 0; i < nodes.length; i++) { + for (let j = i + 1; j < nodes.length; j++) { + links.push([i, j]); + } + } + + // Paths for fallback reroute (detour link when failing node disappears) + const reroute = `M ${nodes[0].x} ${nodes[0].y} + L ${nodes[3].x} ${nodes[3].y} + L ${nodes[2].x} ${nodes[2].y}`; + + const line = (i: number, j: number) => + `M ${nodes[i].x} ${nodes[i].y} L ${nodes[j].x} ${nodes[j].y}`; + + const failRay = `M ${failing.x} ${failing.y} L ${nodes[1].x} ${nodes[1].y}`; + + return ( +
+ + {/* ===== GRID + FILTERS ===== */} + + + + + + + + + + + + + + + + + + + + + + {/* ===== BASE LINKS (Healthy Mesh) ===== */} + {links.map(([i, j], idx) => ( + + ))} + + {/* ===== FAILING NODE LINK (Fading Out) ===== */} + + + {/* ===== ACTIVE REROUTE (Compensating Path) ===== */} + + + {/* ===== MOVING PACKETS ON HEALTHY LINKS ===== */} + {!prefers && + links.map(([i, j], idx) => ( + + ))} + + {/* ===== PACKETS ON REROUTE WHEN FAILURE OCCURS ===== */} + {!prefers && ( + + )} + + {/* ===== HEALTHY NODES ===== */} + {nodes.map((n, i) => ( + + {/* Aura */} + {!prefers && ( + + )} + + {/* Pod body */} + + + {/* Core */} + + + ))} + + {/* ===== FAILING NODE (Flickering / Disconnecting) ===== */} + + + + {!prefers && ( + + )} + + + +
+ ); +} diff --git a/src/pages/pods/animations/Security.tsx b/src/pages/pods/animations/Security.tsx new file mode 100644 index 0000000..eec1e5e --- /dev/null +++ b/src/pages/pods/animations/Security.tsx @@ -0,0 +1,231 @@ +"use client"; + +import { motion, useReducedMotion } from "framer-motion"; +import clsx from "clsx"; + +type Props = { + className?: string; + accent?: string; // cyan + danger?: string; // hostile color + bg?: string; // dark background + gridStroke?: string; // subtle grid +}; + +const W = 720; +const H = 540; + +export default function Security({ + className, + accent = "#00b8db", + danger = "#ff4d4d", + bg = "#0b0b0b", + gridStroke = "#2b2a2a", +}: Props) { + const prefers = useReducedMotion(); + + // Central protected pod + const center = { x: W / 2, y: H / 2 }; + + // External hostile/corporate nodes + const hostile = [ + { x: 160, y: 120 }, + { x: 560, y: 120 }, + { x: 120, y: 300 }, + { x: 600, y: 380 }, + { x: 350, y: 80 }, + ]; + + // Helper function for attack rays + const attackRay = (h: { x: number; y: number }) => + `M ${h.x} ${h.y} L ${center.x} ${center.y}`; + + return ( + + ); +}