Why does Ethereum need a roadmap?
diff --git a/app/[locale]/roadmap/tracks/_components/CustomNodes/EndGoalNode.tsx b/app/[locale]/roadmap/tracks/_components/CustomNodes/EndGoalNode.tsx
new file mode 100644
index 00000000000..e548f4688ae
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/_components/CustomNodes/EndGoalNode.tsx
@@ -0,0 +1,39 @@
+"use client"
+
+import { Handle, Position } from "@xyflow/react"
+
+type EndGoalNodeProps = {
+ data: {
+ label: string
+ leftNode?: boolean
+ }
+}
+
+const EndGoalNode = ({ data }: EndGoalNodeProps) => {
+ return (
+ <>
+ {data.leftNode && (
+
+ )}
+
+ >
+ )
+}
+
+export default EndGoalNode
diff --git a/app/[locale]/roadmap/tracks/_components/CustomNodes/FeatureResearchNode.tsx b/app/[locale]/roadmap/tracks/_components/CustomNodes/FeatureResearchNode.tsx
new file mode 100644
index 00000000000..99c99e30085
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/_components/CustomNodes/FeatureResearchNode.tsx
@@ -0,0 +1,109 @@
+"use client"
+
+import { Handle, Position } from "@xyflow/react"
+
+type FeatureResearchNodeProps = {
+ data: {
+ label: string
+ topNode: boolean
+ leftNode: boolean
+ rightNode: boolean
+ bottomNode: boolean
+ }
+}
+
+const FeatureResearchNode = ({ data }: FeatureResearchNodeProps) => {
+ const { topNode, leftNode, rightNode, bottomNode } = data
+
+ return (
+ <>
+ {topNode && (
+
+ )}
+ {topNode && (
+
+ )}
+ {leftNode && (
+
+ )}
+ {rightNode && (
+
+ )}
+ {bottomNode && (
+
+ )}
+
+ >
+ )
+}
+
+export default FeatureResearchNode
diff --git a/app/[locale]/roadmap/tracks/_components/CustomNodes/FeatureScheduledNode.tsx b/app/[locale]/roadmap/tracks/_components/CustomNodes/FeatureScheduledNode.tsx
new file mode 100644
index 00000000000..6af70b50c64
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/_components/CustomNodes/FeatureScheduledNode.tsx
@@ -0,0 +1,88 @@
+"use client"
+
+import { Handle, Position } from "@xyflow/react"
+
+type FeatureScheduledNodeProps = {
+ data: {
+ label: string
+ topNode: boolean
+ leftNode: boolean
+ rightNode: boolean
+ bottomNode: boolean
+ }
+}
+
+const FeatureScheduledNode = ({ data }: FeatureScheduledNodeProps) => {
+ const { topNode, leftNode, rightNode, bottomNode } = data
+
+ return (
+ <>
+ {topNode && (
+
+ )}
+ {leftNode && (
+
+ )}
+ {rightNode && (
+
+ )}
+ {bottomNode && (
+
+ )}
+
+ >
+ )
+}
+
+export default FeatureScheduledNode
diff --git a/app/[locale]/roadmap/tracks/_components/CustomNodes/FeatureShippedNode.tsx b/app/[locale]/roadmap/tracks/_components/CustomNodes/FeatureShippedNode.tsx
new file mode 100644
index 00000000000..6f038b822df
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/_components/CustomNodes/FeatureShippedNode.tsx
@@ -0,0 +1,88 @@
+"use client"
+
+import { Handle, Position } from "@xyflow/react"
+
+type FeatureShippedNodeProps = {
+ data: {
+ label: string
+ topNode: boolean
+ leftNode: boolean
+ rightNode: boolean
+ bottomNode: boolean
+ }
+}
+
+const FeatureShippedNode = ({ data }: FeatureShippedNodeProps) => {
+ const { topNode, leftNode, rightNode, bottomNode } = data
+
+ return (
+ <>
+ {topNode && (
+
+ )}
+ {leftNode && (
+
+ )}
+ {rightNode && (
+
+ )}
+ {bottomNode && (
+
+ )}
+
+ >
+ )
+}
+
+export default FeatureShippedNode
diff --git a/app/[locale]/roadmap/tracks/_components/CustomNodes/GroupNode.tsx b/app/[locale]/roadmap/tracks/_components/CustomNodes/GroupNode.tsx
new file mode 100644
index 00000000000..e8bdee04c8c
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/_components/CustomNodes/GroupNode.tsx
@@ -0,0 +1,52 @@
+import { Handle, Position } from "@xyflow/react"
+
+type GroupNodeProps = {
+ data: {
+ label: string
+ }
+}
+
+const GroupNode = ({ data }: GroupNodeProps) => {
+ return (
+ <>
+
+
+
+
+ >
+ )
+}
+
+export default GroupNode
diff --git a/app/[locale]/roadmap/tracks/_components/CustomNodes/RollupStageNode.tsx b/app/[locale]/roadmap/tracks/_components/CustomNodes/RollupStageNode.tsx
new file mode 100644
index 00000000000..66b3eb5fd63
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/_components/CustomNodes/RollupStageNode.tsx
@@ -0,0 +1,52 @@
+"use client"
+
+import { Handle, Position } from "@xyflow/react"
+
+type RollupStageNodeProps = {
+ data: {
+ label: string
+ stage: string
+ percentage: number
+ rightNode: boolean
+ }
+}
+
+const RollupStageNode = ({ data }: RollupStageNodeProps) => {
+ const { rightNode, percentage, stage, label } = data
+
+ return (
+ <>
+ {rightNode && (
+
+ )}
+
+ >
+ )
+}
+
+export default RollupStageNode
diff --git a/app/[locale]/roadmap/tracks/_components/CustomNodes/TaskIdeaNode.tsx b/app/[locale]/roadmap/tracks/_components/CustomNodes/TaskIdeaNode.tsx
new file mode 100644
index 00000000000..fae6136b462
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/_components/CustomNodes/TaskIdeaNode.tsx
@@ -0,0 +1,89 @@
+"use client"
+
+import { Handle, Position } from "@xyflow/react"
+
+type TaskIdeaNodeProps = {
+ data: {
+ label: string
+ topNode: boolean
+ leftNode: boolean
+ rightNode: boolean
+ bottomNode: boolean
+ }
+}
+
+const TaskIdeaNode = ({ data }: TaskIdeaNodeProps) => {
+ const { topNode, leftNode, rightNode, bottomNode } = data
+
+ return (
+ <>
+ {topNode && (
+
+ )}
+ {leftNode && (
+
+ )}
+ {rightNode && (
+
+ )}
+ {bottomNode && (
+
+ )}
+
+ >
+ )
+}
+
+export default TaskIdeaNode
diff --git a/app/[locale]/roadmap/tracks/_components/CustomNodes/TaskResearchNode.tsx b/app/[locale]/roadmap/tracks/_components/CustomNodes/TaskResearchNode.tsx
new file mode 100644
index 00000000000..57a95f4d27b
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/_components/CustomNodes/TaskResearchNode.tsx
@@ -0,0 +1,100 @@
+"use client"
+
+import { Handle, Position } from "@xyflow/react"
+
+type TaskResearchNodeProps = {
+ data: {
+ label: string
+ percentage: number
+ topNode: boolean
+ leftNode: boolean
+ rightNode: boolean
+ bottomNode: boolean
+ }
+}
+
+const TaskResearchNode = ({ data }: TaskResearchNodeProps) => {
+ const { topNode, leftNode, rightNode, bottomNode, percentage } = data
+
+ return (
+ <>
+ {topNode && (
+
+ )}
+ {leftNode && (
+
+ )}
+ {rightNode && (
+
+ )}
+ {bottomNode && (
+
+ )}
+
+ {/* Progress background */}
+
+
+
+
+ >
+ )
+}
+
+export default TaskResearchNode
diff --git a/app/[locale]/roadmap/tracks/_components/CustomNodes/TaskScheduledNode.tsx b/app/[locale]/roadmap/tracks/_components/CustomNodes/TaskScheduledNode.tsx
new file mode 100644
index 00000000000..1677a1e04e7
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/_components/CustomNodes/TaskScheduledNode.tsx
@@ -0,0 +1,88 @@
+"use client"
+
+import { Handle, Position } from "@xyflow/react"
+
+type TaskScheduledNodeProps = {
+ data: {
+ label: string
+ topNode: boolean
+ leftNode: boolean
+ rightNode: boolean
+ bottomNode: boolean
+ }
+}
+
+const TaskScheduledNode = ({ data }: TaskScheduledNodeProps) => {
+ const { topNode, leftNode, rightNode, bottomNode } = data
+
+ return (
+ <>
+ {topNode && (
+
+ )}
+ {leftNode && (
+
+ )}
+ {rightNode && (
+
+ )}
+ {bottomNode && (
+
+ )}
+
+ >
+ )
+}
+
+export default TaskScheduledNode
diff --git a/app/[locale]/roadmap/tracks/_components/CustomNodes/TaskShippedNode.tsx b/app/[locale]/roadmap/tracks/_components/CustomNodes/TaskShippedNode.tsx
new file mode 100644
index 00000000000..604e084cd9a
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/_components/CustomNodes/TaskShippedNode.tsx
@@ -0,0 +1,88 @@
+"use client"
+
+import { Handle, Position } from "@xyflow/react"
+
+type TaskShippedNodeProps = {
+ data: {
+ label: string
+ topNode: boolean
+ leftNode: boolean
+ rightNode: boolean
+ bottomNode: boolean
+ }
+}
+
+const TaskShippedNode = ({ data }: TaskShippedNodeProps) => {
+ const { topNode, leftNode, rightNode, bottomNode } = data
+
+ return (
+ <>
+ {topNode && (
+
+ )}
+ {leftNode && (
+
+ )}
+ {rightNode && (
+
+ )}
+ {bottomNode && (
+
+ )}
+
+ >
+ )
+}
+
+export default TaskShippedNode
diff --git a/app/[locale]/roadmap/tracks/_components/CustomNodes/TrackNode.tsx b/app/[locale]/roadmap/tracks/_components/CustomNodes/TrackNode.tsx
new file mode 100644
index 00000000000..889d6146938
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/_components/CustomNodes/TrackNode.tsx
@@ -0,0 +1,93 @@
+"use client"
+
+import { Handle, Position } from "@xyflow/react"
+
+type TrackNodeProps = {
+ data: {
+ label: string
+ sublabel: string
+ topNode: boolean
+ leftNode: boolean
+ rightNode: boolean
+ bottomNode: boolean
+ }
+}
+
+const TrackNode = ({ data }: TrackNodeProps) => {
+ const { topNode, leftNode, rightNode, bottomNode } = data
+
+ return (
+ <>
+ {topNode && (
+
+ )}
+ {leftNode && (
+
+ )}
+ {rightNode && (
+
+ )}
+ {bottomNode && (
+
+ )}
+
+
+
{data.label}
+
{data.sublabel}
+
+
+ >
+ )
+}
+
+export default TrackNode
diff --git a/app/[locale]/roadmap/tracks/_components/CustomNodes/index.ts b/app/[locale]/roadmap/tracks/_components/CustomNodes/index.ts
new file mode 100644
index 00000000000..6c1ec9db19e
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/_components/CustomNodes/index.ts
@@ -0,0 +1,25 @@
+import EndGoalNode from "./EndGoalNode"
+import FeatureResearchNode from "./FeatureResearchNode"
+import FeatureScheduledNode from "./FeatureScheduledNode"
+import FeatureShippedNode from "./FeatureShippedNode"
+import GroupNode from "./GroupNode"
+import RollupStageNode from "./RollupStageNode"
+import TaskIdeaNode from "./TaskIdeaNode"
+import TaskResearchNode from "./TaskResearchNode"
+import TaskScheduledNode from "./TaskScheduledNode"
+import TaskShippedNode from "./TaskShippedNode"
+import TrackNode from "./TrackNode"
+
+export {
+ EndGoalNode,
+ FeatureResearchNode,
+ FeatureScheduledNode,
+ FeatureShippedNode,
+ GroupNode,
+ RollupStageNode,
+ TaskIdeaNode,
+ TaskResearchNode,
+ TaskScheduledNode,
+ TaskShippedNode,
+ TrackNode,
+}
diff --git a/app/[locale]/roadmap/tracks/_components/TrackNodeSetups/MergeTrackNodes.ts b/app/[locale]/roadmap/tracks/_components/TrackNodeSetups/MergeTrackNodes.ts
new file mode 100644
index 00000000000..bb67f6b4482
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/_components/TrackNodeSetups/MergeTrackNodes.ts
@@ -0,0 +1,425 @@
+import { MarkerType } from "@xyflow/react"
+import { Edge, Node } from "@xyflow/react"
+const mergeNodes: Node[] = [
+ {
+ id: "1",
+ position: { x: 20, y: 150 },
+ type: "taskShipped",
+ data: {
+ label: "Beacon chain launch",
+ track: "Merge",
+ rightNode: true,
+ description: [
+ "The Beacon Chain introduced proof-of-stake to Ethereum, running in parallel with the existing proof-of-work chain. It allowed anyone to stake 32 ETH, started producing proof-of-stake blocks, and later enabled The Merge.",
+ "The Beacon Chain became Ethereum's new consensus mechanism, managing the network of validators. For over a year, it existed alongside the original Ethereum chain without processing user transactions, until both chains joined together during The Merge.",
+ ],
+ releaseDate: "December 1, 2020",
+ releaseLabel: "Beacon Chain genesis",
+ releasePageURL: "/roadmap/beacon-chain/",
+ benefits: [
+ "Introduced proof-of-stake to Ethereum",
+ "Allowed anyone to stake 32 ETH",
+ "Enabled The Merge",
+ ],
+ furtherReading: [
+ {
+ title: "Beacon Chain",
+ url: "/roadmap/beacon-chain/",
+ },
+ {
+ title: "EF blog announcement",
+ url: "https://blog.ethereum.org/2020/11/27/eth2-quick-update-no-21/",
+ },
+ ],
+ },
+ },
+ {
+ id: "2",
+ position: { x: 250, y: 150 },
+ type: "taskShipped",
+ data: {
+ label: "Warmup fork (Altair)",
+ track: "Merge",
+ leftNode: true,
+ rightNode: true,
+ description: [
+ `Altair was the first update to the Beacon Chain. It added "sync committees" to help light clients follow the chain efficiently, improved validator rewards, and was a test run for future consensus-layer updates.`,
+ `Altair changed the validator penalties and rewards system, refining the initial values set at the Beacon Chain’s launch. The Altair showed the consensus layer could upgrade without problems, helping to build confidence for the Merge.`,
+ ],
+ releaseDate: "December 8, 2021",
+ releaseLabel: "Altair",
+ releasePageURL: "/history/#altair",
+ benefits: [
+ "Added sync committees to help light clients follow the chain efficiently",
+ "Improved validator rewards",
+ "Was a test run for future consensus-layer updates",
+ ],
+ furtherReading: [
+ {
+ title: "Altair Mainnet announcement",
+ url: "https://blog.ethereum.org/2021/10/05/altair-announcement",
+ },
+ ],
+ },
+ },
+ {
+ id: "3",
+ position: { x: 480, y: 123.5 },
+ type: "featureShipped",
+ data: {
+ label: "Merge!\nNo more PoW",
+ track: "Merge",
+ leftNode: true,
+ rightNode: true,
+ description: [
+ "The Merge swapped Ethereum's consensus mechanism from proof-of-work to proof-of-stake, connecting the original execution layer to the Beacon Chain.",
+ "The Merge reduced Ethereum's energy consumption by ~99.95%, making Ethereum environmentally sustainable and more secure by requiring validators stake ETH as collateral that can be destroyed if they act maliciously.",
+ ],
+ releaseDate: "September 15, 2022",
+ releaseLabel: "The Merge",
+ releasePageURL: "/roadmap/merge/",
+ benefits: [
+ "~99.95% reduction in energy usage",
+ "Security through staked ETH",
+ ],
+ furtherReading: [
+ {
+ title: "The Merge",
+ url: "/roadmap/merge/",
+ },
+ {
+ title: "Mainnet Merge announcement",
+ url: "https://blog.ethereum.org/2022/08/24/mainnet-merge-announcement/",
+ },
+ ],
+ },
+ },
+ {
+ id: "4",
+ position: { x: 720, y: 123.5 },
+ type: "taskShipped",
+ data: {
+ label: "Distributed validators",
+ track: "Merge",
+ description: [
+ "Distributed validator technology (DVT) lets multiple operators run a single validator together. It splits validator responsibilities across separate machines, improving security and reducing the risk of slashing penalties.",
+ "DVT makes Ethereum more resilient by eliminating single points of failure. If one machine in a DVT validator goes offline, the others can continue working, ensuring the validator stays active and avoids penalties for downtime.",
+ ],
+ releaseDate: "TODO",
+ releaseLabel: "TODO",
+ releasePageURL: "/staking/dvt/",
+ benefits: [
+ "Increased validator reliability",
+ "Better network decentralization",
+ "Lower barrier to participation",
+ ],
+ furtherReading: [
+ {
+ title: "Distributed validator technology (DVT)",
+ url: "/staking/dvt/",
+ },
+ ],
+ },
+ },
+ {
+ id: "5",
+ position: { x: 720, y: 250 },
+ type: "taskShipped",
+ data: {
+ label: "Withdrawals",
+ track: "Merge",
+ leftNode: true,
+ description: [
+ "Enabling withdrawals allowed validators to access their staked ETH and rewards that were previously locked indefinitely on the Beacon Chain.",
+ "This made staking more flexible making the network stronger, more appealing for staking, and increasing the number of people staking on Ethereum.",
+ ],
+ releaseDate: "April 12, 2023",
+ releaseLabel: "Shapella",
+ releasePageURL: "/history/#shapella",
+ benefits: [
+ "Access to staked ETH and rewards",
+ "Reduced staking risk",
+ "Increased staking participation",
+ ],
+ furtherReading: [
+ {
+ title: "Staking withdrawals",
+ url: "/staking/withdrawals/",
+ },
+ {
+ title: "Shapella announcement",
+ url: "https://blog.ethereum.org/2023/03/28/shapella-mainnet-announcement",
+ },
+ ],
+ },
+ },
+ {
+ id: "6",
+ position: { x: 950, y: 150 },
+ type: "taskResearch",
+ data: {
+ label: "Per-slot participant selection",
+ track: "Merge",
+ rightNode: true,
+ percentage: 45,
+ description: [
+ "Per-slot participant selection will choose which validators participate in consensus for each 12-second slot. Instead of all validators being active at once, the network will select an optimal subset to handle attestations and block validation.",
+ "This approach reduces network communication overhead while maintaining security. By carefully selecting which validators are active in each slot, Ethereum can support a much larger total validator set without overwhelming the network with coordination messages.",
+ ],
+ releaseDate: "2026",
+ benefits: ["Support for more validators", "Reduced network congestion"],
+ furtherReading: [
+ {
+ title:
+ "Vorbit: SSF with circular and spiral finality validator selection and distribution",
+ url: "https://ethresear.ch/t/vorbit-ssf-with-circular-and-spiral-finality-validator-selection-and-distribution/20464",
+ },
+ {
+ title: "Sticking to 8192 signatures per slot post-SSF: how and why",
+ url: "https://ethresear.ch/t/sticking-to-8192-signatures-per-slot-post-ssf-how-and-why/17989",
+ },
+ ],
+ },
+ },
+ {
+ id: "7",
+ position: { x: 950, y: 50 },
+ type: "taskResearch",
+ data: {
+ label: "SSF specification",
+ track: "Merge",
+ rightNode: true,
+ percentage: 30,
+ description: [
+ "The SSF specification defines the technical standards and implementation details for achieving single slot finality on Ethereum. It outlines changes to validator responsibilities, consensus rules, and network communication.",
+ "This specification will establish how validators coordinate to achieve finality in a single 12-second slot, including voting mechanisms, thresholds, and fault tolerance parameters.",
+ ],
+ releaseDate: "2026",
+ benefits: [
+ "Client teams can start implementing, knowing the design won’t change",
+ "Audits and testnets can begin",
+ ],
+ furtherReading: [
+ {
+ title: "Paths to SSF revisited",
+ url: "https://ethresear.ch/t/paths-to-ssf-revisited/22052",
+ },
+ ],
+ },
+ },
+ {
+ id: "8",
+ position: { x: 950, y: 290 },
+ type: "taskIdea",
+ data: {
+ label: "Implementation",
+ track: "Merge",
+ rightNode: true,
+ description: [
+ "Once the SSF specification is complete, core devs can begin implementing SSF into client software. This phase involves turning the research and specifications into working code that can be deployed on the network.",
+ "Implementation will require extensive testing across multiple client teams, coordination between consensus and execution layers, and careful validation to ensure the upgrade works safely. This engineering work will make 12-second finality a reality for Ethereum users.",
+ ],
+ releaseDate: "2026",
+ benefits: [
+ "Working SSF code in clients",
+ "Extensive testing and validation",
+ ],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "9",
+ position: { x: 1175, y: 133.2 },
+ type: "featureResearch",
+ data: {
+ label: "Single slot finality (SSF)",
+ track: "Merge",
+ topNode: true,
+ leftNode: true,
+ bottomNode: true,
+ description: [
+ "Single slot finality (SSF) will reduce Ethereum's time to finality from 15 minutes to a single 12-second slot. This upgrade would allow transactions to become irreversible much faster than is currently possible.",
+ "By finalizing blocks in a single slot, SSF would improve user experience, reduce MEV opportunities, and strengthen Ethereum's security. This significant improvement to Ethereum's consensus mechanism represents one of the most important upgrades on the post-Merge roadmap.",
+ ],
+ releaseDate: "2027/2028",
+ benefits: [
+ "12-second transaction finality",
+ "Better user experience",
+ "Reduced MEV opportunities",
+ ],
+ furtherReading: [
+ {
+ title: "Single slot finality",
+ url: "/roadmap/single-slot-finality/#single-slot-finality",
+ },
+ ],
+ },
+ },
+ {
+ id: "10",
+ position: { x: 1175, y: -30 },
+ type: "taskResearch",
+ data: {
+ label: "Secret leader election",
+ track: "Merge",
+ percentage: 70,
+ description: [
+ "Secret leader election prevents validators from knowing who will propose the next block until just before block creation time. This protects block proposers from targeted attacks that could disrupt network operations.",
+ "Hiding the identity of upcoming block proposers prevents attackers from targeted denial-of-service (DoS) attacks and front-running.",
+ ],
+ releaseDate: "2028",
+ benefits: [
+ "Protection from targeted attacks",
+ "Reduced denial-of-service risks",
+ "Block production guarantees",
+ ],
+ furtherReading: [
+ {
+ title: "Secret leader election",
+ url: "/roadmap/secret-leader-election/",
+ },
+ {
+ title: "Ethereum Research: Single secret leader election",
+ url: "https://ethresear.ch/tag/single-secret-leader-election",
+ },
+ ],
+ },
+ },
+ {
+ id: "11",
+ position: { x: 1400, y: 250 },
+ type: "taskResearch",
+ data: {
+ label: "Increase validator count",
+ track: "Merge",
+ percentage: 50,
+ description: [
+ "The goal is to dramatically increase the number of validators securing Ethereum from today's ~1 million to potentially millions more. This requires solving network communication bottlenecks that currently limit how many validators can efficiently participate in consensus.",
+ "By enabling more people to become validators, Ethereum becomes more decentralized and secure. A larger, more diverse validator set makes Ethereum harder to attack and ensures no single group can control consensus, strengthening Ethereum's decentralization.",
+ ],
+ releaseDate: "2028",
+ benefits: ["More validators", "More decentralized", "More secure"],
+ furtherReading: [
+ {
+ title:
+ "Orbit: SSF solo staking friendly validator set management for SSF",
+ url: "https://ethresear.ch/t/orbit-ssf-solo-staking-friendly-validator-set-management-for-ssf/19928",
+ },
+ ],
+ },
+ },
+ {
+ id: "12",
+ position: { x: 1420, y: 70 },
+ type: "endGoal",
+ data: {
+ label: "Increase validator count",
+ track: "Merge",
+ percentage: 50,
+ description: [
+ "The goal is to dramatically increase the number of validators securing Ethereum from today's ~1 million to potentially millions more. This requires solving network communication bottlenecks that currently limit how many validators can efficiently participate in consensus.",
+ "By enabling more people to become validators, Ethereum becomes more decentralized and secure. A larger, more diverse validator set makes Ethereum harder to attack and ensures no single group can control consensus, strengthening Ethereum's decentralization.",
+ ],
+ releaseDate: "2028",
+ benefits: ["More validators", "More decentralized", "More secure"],
+ furtherReading: [
+ {
+ title:
+ "Orbit: SSF solo staking friendly validator set management for SSF",
+ url: "https://ethresear.ch/t/orbit-ssf-solo-staking-friendly-validator-set-management-for-ssf/19928",
+ },
+ ],
+ },
+ },
+]
+
+const mergeEdges: Edge[] = [
+ {
+ id: "e1-2",
+ source: "1",
+ target: "2",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--success))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--success))" },
+ },
+ {
+ id: "e2-3",
+ source: "2",
+ target: "3",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--success))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--success))" },
+ },
+ {
+ id: "e3-4",
+ source: "3",
+ target: "5",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--success))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--success))" },
+ },
+ {
+ id: "e6-9",
+ source: "6",
+ target: "9",
+ targetHandle: "left",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "e7-9",
+ source: "7",
+ target: "9",
+ targetHandle: "top",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "e8-9",
+ source: "8",
+ target: "9",
+ targetHandle: "bottom",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+]
+
+export { mergeEdges, mergeNodes }
diff --git a/app/[locale]/roadmap/tracks/_components/TrackNodeSetups/PurgeTrackNodes.ts b/app/[locale]/roadmap/tracks/_components/TrackNodeSetups/PurgeTrackNodes.ts
new file mode 100644
index 00000000000..5150d27ec84
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/_components/TrackNodeSetups/PurgeTrackNodes.ts
@@ -0,0 +1,524 @@
+import { MarkerType } from "@xyflow/react"
+import { Edge, Node } from "@xyflow/react"
+
+const purgeNodes: Node[] = [
+ {
+ id: "1",
+ position: { x: 20, y: 20 },
+ type: "track",
+ data: {
+ label: "The Verge",
+ track: "Verge",
+ sublabel: "Verkle trees",
+ bottomNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "group-1",
+ position: { x: 180, y: 140 },
+ style: {
+ width: 616,
+ height: 164,
+ border: "1px solid hsla(var(--primary))",
+ borderRadius: "10px",
+ backgroundColor: "#B38DF01A",
+ },
+ type: "group",
+ data: {
+ label: "EVM simplification track",
+ },
+ },
+ {
+ id: "2",
+ position: { x: 20, y: 50 },
+ type: "taskShipped",
+ data: {
+ label: "Ban SELF-DESTRUCT",
+ track: "Purge",
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ releaseLabel: "TODO",
+ releasePageURL: "/",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-1",
+ extent: "parent" as const,
+ },
+ {
+ id: "3",
+ position: { x: 220, y: 50 },
+ type: "taskResearch",
+ data: {
+ label: "Simplify gas mechanics",
+ track: "Purge",
+ percentage: 25,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-1",
+ extent: "parent" as const,
+ },
+ {
+ id: "4",
+ position: { x: 420, y: 50 },
+ type: "taskResearch",
+ data: {
+ label: "Precompiles -> EVM impls",
+ track: "Purge",
+ percentage: 25,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-1",
+ extent: "parent" as const,
+ },
+ {
+ id: "5",
+ position: { x: 100, y: 350 },
+ type: "taskShipped",
+ data: {
+ label: "EIP-4844 specification",
+ track: "Purge",
+ rightNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ releaseLabel: "TODO",
+ releasePageURL: "/",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "6",
+ position: { x: 330, y: 350 },
+ type: "taskResearch",
+ data: {
+ label: "EIP-4444 implementation",
+ track: "Purge",
+ leftNode: true,
+ rightNode: true,
+ percentage: 80,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "7",
+ position: { x: 600, y: 350 },
+ type: "featureResearch",
+ data: {
+ label: "History expiry (EIP-4444)",
+ track: "Purge",
+ leftNode: true,
+ bottomNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "8",
+ position: { x: 330, y: 480 },
+ type: "taskShipped",
+ data: {
+ label: "P2P history (eg. Portal)",
+ track: "Purge",
+ rightNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ releaseLabel: "TODO",
+ releasePageURL: "/",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "9",
+ position: { x: 330, y: 600 },
+ type: "taskShipped",
+ data: {
+ label: "Beacon chain fast sync",
+ track: "Purge",
+ rightNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ releaseLabel: "TODO",
+ releasePageURL: "/",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "10",
+ position: { x: 100, y: 480 },
+ type: "taskShipped",
+ data: {
+ label: "Eliminate most gas refunds",
+ track: "Purge",
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ releaseLabel: "TODO",
+ releasePageURL: "/",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "11",
+ position: { x: 800, y: 460 },
+ type: "track",
+ data: {
+ label: "The Splurge",
+ track: "Splurge",
+ sublabel: "Endgame EVM",
+ topNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "12",
+ position: { x: 1000, y: 200 },
+ type: "taskResearch",
+ data: {
+ label: "Address space extension",
+ track: "Purge",
+ rightNode: true,
+ percentage: 20,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "13",
+ position: { x: 1220, y: 209.5 },
+ type: "taskResearch",
+ data: {
+ label: "State expiry",
+ track: "Purge",
+ leftNode: true,
+ percentage: 20,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "14",
+ position: { x: 1000, y: 320 },
+ type: "taskResearch",
+ data: {
+ label: "LOG reform",
+ track: "Purge",
+ percentage: 20,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "15",
+ position: { x: 1000, y: 420 },
+ type: "taskResearch",
+ data: {
+ label: "Remove old Tx types",
+ track: "Purge",
+ rightNode: true,
+ percentage: 20,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "16",
+ position: { x: 1220, y: 420 },
+ type: "taskResearch",
+ data: {
+ label: "Serialization harmonization",
+ track: "Purge",
+ leftNode: true,
+ percentage: 20,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+]
+
+const purgeEdges: Edge[] = [
+ {
+ id: "e-group-1-1",
+ source: "group-1",
+ sourceHandle: "left",
+ target: "1",
+ targetHandle: "bottom",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))", strokeDasharray: "5,5" },
+ },
+ {
+ id: "e5-6",
+ source: "5",
+ target: "6",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--success))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--success))" },
+ },
+ {
+ id: "e8-7",
+ source: "8",
+ target: "7",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--success))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--success))" },
+ },
+ {
+ id: "e6-7",
+ source: "6",
+ target: "7",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "e9-7",
+ source: "9",
+ target: "7",
+ targetHandle: "bottom",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--success))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--success))" },
+ },
+ {
+ id: "e-group-1-11",
+ source: "group-1",
+ sourceHandle: "right",
+ target: "11",
+ targetHandle: "top",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))", strokeDasharray: "5,5" },
+ },
+ {
+ id: "e12-13",
+ source: "12",
+ target: "13",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "e15-16",
+ source: "15",
+ target: "16",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+]
+export { purgeEdges, purgeNodes }
diff --git a/app/[locale]/roadmap/tracks/_components/TrackNodeSetups/ScourgeTrackNodes.ts b/app/[locale]/roadmap/tracks/_components/TrackNodeSetups/ScourgeTrackNodes.ts
new file mode 100644
index 00000000000..6913f92eb72
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/_components/TrackNodeSetups/ScourgeTrackNodes.ts
@@ -0,0 +1,452 @@
+import { MarkerType } from "@xyflow/react"
+import { Edge, Node } from "@xyflow/react"
+
+const scourgeNodes: Node[] = [
+ {
+ id: "group-1",
+ position: { x: 20, y: 20 },
+ style: {
+ width: 1390,
+ height: 356,
+ border: "1px solid hsla(var(--primary))",
+ borderRadius: "10px",
+ backgroundColor: "#B38DF01A",
+ },
+ type: "group",
+ data: {
+ label: "MEV Track",
+ },
+ },
+ {
+ id: "group-2",
+ position: { x: 300, y: 410 },
+ style: {
+ width: 815,
+ height: 164,
+ border: "1px solid hsla(var(--primary))",
+ borderRadius: "10px",
+ backgroundColor: "#B38DF01A",
+ },
+ type: "group",
+ data: {
+ label: "Staking economics / experience track",
+ },
+ },
+ {
+ id: "1",
+ position: { x: 40, y: 160 },
+ type: "taskShipped",
+ data: {
+ label: "Extra-protocol MEV markets",
+ track: "Scourge",
+ rightNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ releaseLabel: "TODO",
+ releasePageURL: "/",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-1",
+ extent: "parent" as const,
+ },
+ {
+ id: "2",
+ position: { x: 270, y: 169.5 },
+ type: "taskResearch",
+ data: {
+ label: "Explore ePBS",
+ track: "Scourge",
+ leftNode: true,
+ rightNode: true,
+ percentage: 50,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-1",
+ extent: "parent" as const,
+ },
+ {
+ id: "3",
+ position: { x: 270, y: 70 },
+ type: "taskResearch",
+ data: {
+ label: "Inclusion lists",
+ track: "Scourge",
+ rightNode: true,
+ percentage: 90,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-1",
+ extent: "parent" as const,
+ },
+ {
+ id: "4",
+ position: { x: 500, y: 160 },
+ type: "taskResearch",
+ data: {
+ label: "Explore MEV burn in ePBS",
+ track: "Scourge",
+ leftNode: true,
+ rightNode: true,
+ percentage: 30,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-1",
+ extent: "parent" as const,
+ },
+ {
+ id: "5",
+ position: { x: 720, y: 20 },
+ type: "taskResearch",
+ data: {
+ label: "Distributed block building",
+ track: "Scourge",
+ rightNode: true,
+ percentage: 20,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-1",
+ extent: "parent" as const,
+ },
+ {
+ id: "6",
+ position: { x: 720, y: 240 },
+ type: "taskResearch",
+ data: {
+ label: "Explore execution tickets",
+ track: "Scourge",
+ rightNode: true,
+ percentage: 20,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-1",
+ extent: "parent" as const,
+ },
+ {
+ id: "7",
+ position: { x: 950, y: 80 },
+ type: "featureResearch",
+ data: {
+ label: "Explore execution tickets",
+ track: "Scourge",
+ leftNode: true,
+ percentage: 20,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-1",
+ extent: "parent" as const,
+ },
+ {
+ id: "8",
+ position: { x: 1175, y: 40 },
+ type: "taskResearch",
+ data: {
+ label: "App-layer MEV minimization",
+ track: "Scourge",
+ percentage: 20,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-1",
+ extent: "parent" as const,
+ },
+ {
+ id: "9",
+ position: { x: 1175, y: 200 },
+ type: "taskResearch",
+ data: {
+ label: "Explore pre-confirmations",
+ track: "Scourge",
+ percentage: 20,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-1",
+ extent: "parent" as const,
+ },
+ {
+ id: "10",
+ position: { x: 20, y: 45 },
+ type: "taskScheduled",
+ data: {
+ label: "Raise max effective balance",
+ track: "Scourge",
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-2",
+ extent: "parent" as const,
+ },
+ {
+ id: "11",
+ position: { x: 220, y: 45 },
+ type: "taskResearch",
+ data: {
+ label: "Improve node operator usability",
+ track: "Scourge",
+ percentage: 80,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-2",
+ extent: "parent" as const,
+ },
+ {
+ id: "12",
+ position: { x: 420, y: 45 },
+ type: "taskResearch",
+ data: {
+ label: "Explore total stake capping",
+ track: "Scourge",
+ percentage: 20,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-2",
+ extent: "parent" as const,
+ },
+ {
+ id: "13",
+ position: { x: 620, y: 25 },
+ type: "taskResearch",
+ data: {
+ label: "Explore solutions to liquid staking centralization",
+ track: "Scourge",
+ percentage: 60,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-2",
+ extent: "parent" as const,
+ },
+]
+
+const scourgeEdges: Edge[] = [
+ {
+ id: "1-2",
+ source: "1",
+ target: "2",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--success))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--success))" },
+ },
+ {
+ id: "2-4",
+ source: "2",
+ target: "4",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "3-7",
+ source: "3",
+ target: "7",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "4-7",
+ source: "4",
+ target: "7",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "5-7",
+ source: "5",
+ target: "7",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "6-7",
+ source: "6",
+ target: "7",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+]
+
+export { scourgeEdges, scourgeNodes }
diff --git a/app/[locale]/roadmap/tracks/_components/TrackNodeSetups/SplurgeTrackNodes.ts b/app/[locale]/roadmap/tracks/_components/TrackNodeSetups/SplurgeTrackNodes.ts
new file mode 100644
index 00000000000..59402bee969
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/_components/TrackNodeSetups/SplurgeTrackNodes.ts
@@ -0,0 +1,441 @@
+import { MarkerType } from "@xyflow/react"
+import { Edge, Node } from "@xyflow/react"
+
+const splurgeNodes: Node[] = [
+ {
+ id: "group-1",
+ position: { x: 20, y: 20 },
+ style: {
+ width: 615,
+ height: 150,
+ border: "1px solid hsla(var(--primary))",
+ borderRadius: "10px",
+ backgroundColor: "#B38DF01A",
+ },
+ type: "group",
+ data: {
+ label: "EVM Improvements Track",
+ rightNode: true,
+ },
+ },
+ {
+ id: "1",
+ position: { x: 20, y: 40 },
+ type: "taskResearch",
+ data: {
+ label: "EOF",
+ track: "Splurge",
+ percentage: 90,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-1",
+ extent: "parent" as const,
+ },
+ {
+ id: "2",
+ position: { x: 220, y: 30 },
+ type: "taskResearch",
+ data: {
+ label: "Big modular arithmetic",
+ track: "Splurge",
+ percentage: 75,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-1",
+ extent: "parent" as const,
+ },
+ {
+ id: "3",
+ position: { x: 420, y: 30 },
+ type: "taskResearch",
+ data: {
+ label: "Futher EVM improvements",
+ track: "Splurge",
+ percentage: 30,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-1",
+ extent: "parent" as const,
+ },
+ {
+ id: "4",
+ position: { x: 700, y: 19 },
+ type: "featureResearch",
+ data: {
+ label: "Endgame EVM",
+ track: "Splurge",
+ leftNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "group-2",
+ position: { x: 20, y: 214 },
+ style: {
+ width: 615,
+ height: 150,
+ border: "1px solid hsla(var(--primary))",
+ borderRadius: "10px",
+ backgroundColor: "#B38DF01A",
+ },
+ type: "group",
+ data: {
+ label: "Account Abstraction Track",
+ rightNode: true,
+ leftNode: true,
+ },
+ },
+ {
+ id: "5",
+ position: { x: 20, y: 40 },
+ type: "taskShipped",
+ data: {
+ label: "ERC-4337 rollout",
+ track: "Splurge",
+ rightNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ releaseLabel: "TODO",
+ releasePageURL: "/",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-2",
+ extent: "parent" as const,
+ },
+ {
+ id: "6",
+ position: { x: 220, y: 30 },
+ type: "taskScheduled",
+ data: {
+ label: "Voluntary EOA conversion",
+ track: "Splurge",
+ leftNode: true,
+ rightNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-2",
+ extent: "parent" as const,
+ },
+ {
+ id: "7",
+ position: { x: 420, y: 30 },
+ type: "taskScheduled",
+ data: {
+ label: "In-protocol enshrining",
+ track: "Splurge",
+ leftNode: true,
+ rightNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ parentId: "group-2",
+ extent: "parent" as const,
+ },
+ {
+ id: "8",
+ position: { x: 700, y: 200 },
+ type: "featureScheduled",
+ data: {
+ label: "Endgame account abstraction",
+ track: "Splurge",
+ leftNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "9",
+ position: { x: -220, y: 239 },
+ type: "taskShipped",
+ data: {
+ label: "EIP-4337 specification",
+ track: "Splurge",
+ rightNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ releaseLabel: "TODO",
+ releasePageURL: "/",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "10",
+ position: { x: 700, y: 410 },
+ type: "taskResearch",
+ data: {
+ label: "Endgame EIP-1559",
+ track: "Splurge",
+ leftNode: true,
+ percentage: 30,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "11",
+ position: { x: 460, y: 410 },
+ type: "taskShipped",
+ data: {
+ label: "EIP-1559",
+ track: "Splurge",
+ rightNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ releaseLabel: "TODO",
+ releasePageURL: "/",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "12",
+ position: { x: 930, y: 240 },
+ type: "taskResearch",
+ data: {
+ label: "Explore delay-encrypted mempools",
+ track: "Splurge",
+ percentage: 10,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "13",
+ position: { x: 930, y: 390 },
+ type: "taskResearch",
+ data: {
+ label: "VDFs",
+ track: "Splurge",
+ percentage: 30,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "14",
+ position: { x: 930, y: 90 },
+ type: "taskResearch",
+ data: {
+ label: "Explore deep-crypto (eg. obfuscation)",
+ track: "Splurge",
+ percentage: 10,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+]
+
+const splurgeEdges: Edge[] = [
+ {
+ id: "e-group-1-4",
+ source: "group-1",
+ sourceHandle: "right",
+ target: "4",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "e-group-2-8",
+ source: "group-2",
+ sourceHandle: "right",
+ target: "8",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "e-9-group-2",
+ source: "9",
+ target: "group-2",
+ targetHandle: "left-target",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--success))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--success))" },
+ },
+ {
+ id: "e-11-10",
+ source: "11",
+ target: "10",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--success))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--success))" },
+ },
+]
+
+export { splurgeEdges, splurgeNodes }
diff --git a/app/[locale]/roadmap/tracks/_components/TrackNodeSetups/SurgeTrackNodes.ts b/app/[locale]/roadmap/tracks/_components/TrackNodeSetups/SurgeTrackNodes.ts
new file mode 100644
index 00000000000..1d30a34a89a
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/_components/TrackNodeSetups/SurgeTrackNodes.ts
@@ -0,0 +1,371 @@
+import { MarkerType } from "@xyflow/react"
+import { Edge, Node } from "@xyflow/react"
+
+const surgeNodes: Node[] = [
+ {
+ id: "1",
+ position: { x: 20, y: 150 },
+ type: "taskShipped",
+ data: {
+ label: "EIP-4844 specification",
+ track: "Surge",
+ rightNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ releaseLabel: "TODO",
+ releasePageURL: "/",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "2",
+ position: { x: 250, y: 150 },
+ type: "taskShipped",
+ data: {
+ label: "EIP-4844 implementation",
+ track: "Surge",
+ leftNode: true,
+ rightNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ releaseLabel: "TODO",
+ releasePageURL: "/",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "3",
+ position: { x: 480, y: 123.5 },
+ type: "featureShipped",
+ data: {
+ label: "Basic rollup scaling",
+ track: "Surge",
+ leftNode: true,
+ bottomNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ releaseLabel: "TODO",
+ releasePageURL: "/",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "4",
+ position: { x: 700, y: 100 },
+ type: "taskResearch",
+ data: {
+ label: "peerDAS",
+ track: "Surge",
+ rightNode: true,
+ percentage: 65,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "5",
+ position: { x: 700, y: 200 },
+ type: "taskResearch",
+ data: {
+ label: "Efficient DA self-healing",
+ track: "Surge",
+ rightNode: true,
+ percentage: 25,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "6",
+ position: { x: 940, y: 100 },
+ type: "featureResearch",
+ data: {
+ label: "Full rollup scaling",
+ track: "Surge",
+ leftNode: true,
+ bottomNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "7",
+ position: { x: 1165, y: 100 },
+ type: "endGoal",
+ data: {
+ label: "Q-safe, no setup commitments",
+ track: "Surge",
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "8",
+ position: { x: 1150, y: 260 },
+ type: "taskResearch",
+ data: {
+ label: "Improve cross-rollup standards + interop",
+ track: "Surge",
+ percentage: 25,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "9",
+ position: { x: 555, y: 320 },
+ type: "rollupStage",
+ data: {
+ label: "Optimistic rollup fraud provers",
+ stage: "STAGE 0 & 1",
+ track: "Surge",
+ percentage: 65,
+ rightNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "10",
+ position: { x: 555, y: 380 },
+ type: "rollupStage",
+ data: {
+ label: "ZK-EVMs",
+ stage: "STAGE 0",
+ track: "Surge",
+ percentage: 50,
+ rightNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "11",
+ position: { x: 1150, y: 440 },
+ type: "track",
+ data: {
+ label: "The Verge",
+ sublabel: "SNARK for L1 EVM",
+ track: "Verge",
+ topNode: true,
+ description: ["TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+]
+
+const surgeEdges: Edge[] = [
+ {
+ id: "e1-2",
+ source: "1",
+ target: "2",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--success))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--success))" },
+ },
+ {
+ id: "e2-3",
+ source: "2",
+ target: "3",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--success))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--success))" },
+ },
+ {
+ id: "e4-6",
+ source: "4",
+ target: "6",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "e5-6",
+ source: "5",
+ target: "6",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "e9-6",
+ source: "9",
+ target: "6",
+ targetHandle: "bottom",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "e10-6",
+ source: "10",
+ target: "6",
+ targetHandle: "bottom",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "e10-11",
+ source: "10",
+ target: "11",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))", strokeDasharray: "5,5" },
+ },
+]
+
+export { surgeEdges, surgeNodes }
diff --git a/app/[locale]/roadmap/tracks/_components/TrackNodeSetups/VergeTrackNodes.ts b/app/[locale]/roadmap/tracks/_components/TrackNodeSetups/VergeTrackNodes.ts
new file mode 100644
index 00000000000..d7d28620fb9
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/_components/TrackNodeSetups/VergeTrackNodes.ts
@@ -0,0 +1,538 @@
+import { MarkerType } from "@xyflow/react"
+import { Edge, Node } from "@xyflow/react"
+
+const vergeNodes: Node[] = [
+ {
+ id: "1",
+ position: { x: 0, y: 400 },
+ type: "taskShipped",
+ data: {
+ label: "Most serious EVM DoS issues solved",
+ track: "Verge",
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ releaseLabel: "TODO",
+ releasePageURL: "/",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "2",
+ position: { x: 220, y: 390 },
+ type: "taskShipped",
+ data: {
+ label: "Basic light client support (sync committees)",
+ track: "Verge",
+ rightNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ releaseLabel: "TODO",
+ releasePageURL: "/",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "3",
+ position: { x: 460, y: 400 },
+ type: "taskResearch",
+ data: {
+ label: "SNARK-based light clients",
+ track: "Verge",
+ leftNode: true,
+ rightNode: true,
+ percentage: 80,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "4",
+ position: { x: 700, y: 390 },
+ type: "taskIdea",
+ data: {
+ label: "SNARK for consensus state transition",
+ track: "Verge",
+ leftNode: true,
+ rightNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "5",
+ position: { x: 700, y: 248.5 },
+ type: "taskIdea",
+ data: {
+ label: "SNARK for Verkle proofs",
+ track: "Verge",
+ leftNode: true,
+ rightNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "6",
+ position: { x: 460, y: 235 },
+ type: "featureResearch",
+ data: {
+ label: "Verkle trees",
+ track: "Verge",
+ leftNode: true,
+ rightNode: true,
+ topNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "7",
+ position: { x: 220, y: 248.5 },
+ type: "taskResearch",
+ data: {
+ label: "Transition spec + impl",
+ track: "Verge",
+ rightNode: true,
+ percentage: 80,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "8",
+ position: { x: 220, y: 100 },
+ type: "taskResearch",
+ data: {
+ label: "Verkle trees spec + impl",
+ track: "Verge",
+ rightNode: true,
+ percentage: 80,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "9",
+ position: { x: 460, y: 100 },
+ type: "taskResearch",
+ data: {
+ label: "Code chunking + gas cost update",
+ track: "Verge",
+ bottomNode: true,
+ percentage: 50,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "10",
+ position: { x: 700, y: 120 },
+ type: "taskIdea",
+ data: {
+ label: "SNARK for L1 EVM",
+ track: "Verge",
+ rightNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "11",
+ position: { x: 950, y: 209 },
+ type: "featureResearch",
+ data: {
+ label: "Fully SNARKed Ethereum",
+ track: "Verge",
+ rightNode: true,
+ leftNode: true,
+ topNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "12",
+ position: { x: 700, y: 0 },
+ type: "track",
+ data: {
+ label: "The Scourge",
+ sublabel: "Improve operator node usability",
+ track: "Scourge",
+ leftNode: true,
+ rightNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "13",
+ position: { x: 950, y: 430 },
+ type: "taskResearch",
+ data: {
+ label: "SNARK / STARK ASICs",
+ track: "Verge",
+ percentage: 30,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "14",
+ position: { x: 1180, y: 80 },
+ type: "taskIdea",
+ data: {
+ label: "Explore EVM verification precompile",
+ track: "Verge",
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+ {
+ id: "15",
+ position: { x: 1200, y: 226 },
+ type: "endGoal",
+ data: {
+ label: "Quantum-safe SNARKs (eg. STARKs)",
+ track: "Verge",
+ leftNode: true,
+ description: ["TODO: Add description", "TODO: Add description"],
+ releaseDate: "TODO",
+ benefits: ["TODO: Add benefits", "TODO: Add benefits"],
+ furtherReading: [
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ {
+ title: "TODO: Add title",
+ url: "/",
+ },
+ ],
+ },
+ },
+]
+
+const vergeEdges: Edge[] = [
+ {
+ id: "e2-3",
+ source: "2",
+ target: "3",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--success))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--success))" },
+ },
+ {
+ id: "e3-4",
+ source: "3",
+ target: "4",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "e7-6",
+ source: "7",
+ target: "6",
+ targetHandle: "left",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "e8-6",
+ source: "8",
+ target: "6",
+ targetHandle: "left",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "e9-6",
+ source: "9",
+ target: "6",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "e10-11",
+ source: "10",
+ target: "11",
+ targetHandle: "left",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "e5-11",
+ source: "5",
+ target: "11",
+ targetHandle: "left",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "e4-11",
+ source: "4",
+ target: "11",
+ targetHandle: "left",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "e11-12",
+ source: "11",
+ sourceHandle: "top-source",
+ target: "12",
+ targetHandle: "right",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))", strokeDasharray: "5,5" },
+ },
+ {
+ id: "e6-12",
+ source: "6",
+ sourceHandle: "right",
+ target: "12",
+ targetHandle: "left",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))", strokeDasharray: "5,5" },
+ },
+ {
+ id: "e6-5",
+ source: "6",
+ sourceHandle: "right",
+ target: "5",
+ targetHandle: "left",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+ {
+ id: "e11-15",
+ source: "11",
+ sourceHandle: "right",
+ target: "15",
+ type: "smoothstep",
+ markerEnd: {
+ type: MarkerType.Arrow,
+ color: "hsla(var(--primary))",
+ width: 32,
+ height: 32,
+ },
+ style: { stroke: "hsla(var(--primary))" },
+ },
+]
+
+export { vergeEdges, vergeNodes }
diff --git a/app/[locale]/roadmap/tracks/_components/tracks.tsx b/app/[locale]/roadmap/tracks/_components/tracks.tsx
new file mode 100644
index 00000000000..f2bad1b22cf
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/_components/tracks.tsx
@@ -0,0 +1,506 @@
+"use client"
+
+import { cloneElement, useMemo, useState } from "react"
+import { motion } from "framer-motion"
+import isEqual from "lodash/isEqual"
+import { MdClose } from "react-icons/md"
+import {
+ ControlButton,
+ Controls,
+ Node,
+ ReactFlow,
+ useReactFlow,
+} from "@xyflow/react"
+
+import FeedbackCard from "@/components/FeedbackCard"
+import { ContentHero } from "@/components/Hero"
+import MainArticle from "@/components/MainArticle"
+import {
+ Accordion,
+ AccordionContent,
+ AccordionItem,
+ AccordionTrigger,
+} from "@/components/ui/accordion"
+import { Button, ButtonLink } from "@/components/ui/buttons/Button"
+import Link from "@/components/ui/Link"
+import {
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
+} from "@/components/ui/popover"
+
+import { cn } from "@/lib/utils/cn"
+
+import {
+ EndGoalNode,
+ FeatureResearchNode,
+ FeatureScheduledNode,
+ FeatureShippedNode,
+ GroupNode,
+ RollupStageNode,
+ TaskIdeaNode,
+ TaskResearchNode,
+ TaskScheduledNode,
+ TaskShippedNode,
+ TrackNode,
+} from "./CustomNodes"
+import { useTracks } from "./useTracks"
+
+import "@xyflow/react/dist/style.css"
+
+import { useActiveHash } from "@/hooks/useActiveHash"
+
+type NodeData = {
+ label?: string
+ track?: string
+ description?: string[]
+ releaseDate?: string
+ sublabel?: string
+ stage?: string
+ percentage?: number
+ topNode?: boolean
+ leftNode?: boolean
+ rightNode?: boolean
+ bottomNode?: boolean
+ releaseLabel?: string
+ releasePageURL?: string
+ benefits?: string[]
+ furtherReading?: {
+ title: string
+ url: string
+ }[]
+}
+
+const RoadmapTracksPage = () => {
+ const tracks = useTracks()
+ const [openItems, setOpenItems] = useState
(() =>
+ tracks.map(({ key }) => key)
+ )
+ const [selectedNode, setSelectedNode] = useState | null>(null)
+ const nodeTypes = useMemo(
+ () => ({
+ endGoal: EndGoalNode,
+ featureResearch: FeatureResearchNode,
+ featureScheduled: FeatureScheduledNode,
+ featureShipped: FeatureShippedNode,
+ group: GroupNode,
+ rollupStage: RollupStageNode,
+ taskIdea: TaskIdeaNode,
+ taskResearch: TaskResearchNode,
+ taskScheduled: TaskScheduledNode,
+ taskShipped: TaskShippedNode,
+ track: TrackNode,
+ }),
+ []
+ )
+ const activeSection = useActiveHash(
+ tracks.map(({ key }) => key),
+ "0% 0% -70% 0%"
+ ).replace(/^#/, "")
+
+ const popoverConfig = {
+ endGoal: {
+ border: "border-primary",
+ background: "bg-gradient-to-b from-primary-high-contrast/10",
+ pillStyles: "bg-primary text-body-inverse",
+ pillText: "END GOAL",
+ },
+ featureResearch: {
+ border: "border-border",
+ background: "bg-gradient-to-b from-background-medium/10",
+ pillStyles: "bg-background-medium",
+ pillText: "RESEARCH",
+ },
+ featureScheduled: {
+ border: "border-warning",
+ background: "bg-gradient-to-b from-warning/10",
+ pillStyles: "bg-warning",
+ pillText: "SCHEDULED",
+ },
+ featureShipped: {
+ border: "border-success",
+ background: "bg-gradient-to-b from-success/10",
+ pillStyles: "bg-success",
+ pillText: "SHIPPED",
+ },
+ rollupStage: {
+ border: "border-primary-high-contrast",
+ background: "bg-gradient-to-b from-primary-high-contrast/10",
+ pillStyles: "bg-primary-high-contrast text-body-inverse",
+ pillText: "STAGE",
+ },
+ taskIdea: {
+ border: "border-background-highlight",
+ background: "bg-gradient-to-b from-background-high/10",
+ pillStyles: "bg-background-high",
+ pillText: "IDEA",
+ },
+ taskResearch: {
+ border: "border-border",
+ background: "bg-gradient-to-b from-medium/10",
+ pillStyles: "bg-background-medium",
+ pillText: "RESEARCH",
+ },
+ taskScheduled: {
+ border: "border-warning",
+ background: "bg-gradient-to-b from-warning/10",
+ pillStyles: "bg-warning",
+ pillText: "SCHEDULED",
+ },
+ taskShipped: {
+ border: "border-success",
+ background: "bg-gradient-to-b from-success/10",
+ pillStyles: "bg-success",
+ pillText: "SHIPPED",
+ },
+ track: {
+ border: "border-primary",
+ background: "bg-gradient-to-b from-primary-high-contrast/10",
+ pillStyles: "bg-primary-high-contrast text-body-inverse",
+ pillText: "TRACK",
+ },
+ }
+
+ const progressBar = (track) => {
+ const nodes = track.nodes.nodes.filter(
+ (node) =>
+ node.type !== "track" &&
+ node.type !== "group" &&
+ node.type !== "featureResearch"
+ )
+ const completionPercentage =
+ nodes.reduce((acc, node) => {
+ if (node.type.includes("Shipped")) {
+ return acc + 100
+ }
+ if (node.type.includes("Scheduled")) {
+ return acc + 100
+ }
+ if (node.type.includes("Research")) {
+ return acc + node.data.percentage
+ }
+ return acc
+ }, 0) / nodes.length
+
+ return {
+ percentage: Math.round(completionPercentage),
+ textColor: completionPercentage >= 50 ? "text-success" : "text-warning",
+ backgroundColor:
+ completionPercentage >= 50 ? "bg-success/20" : "bg-warning/20",
+ progressColor: completionPercentage >= 50 ? "bg-success" : "bg-warning",
+ }
+ }
+
+ const CustomControls = () => {
+ const { zoomIn, zoomOut } = useReactFlow()
+
+ return (
+
+ zoomOut()}
+ className="rounded-full !border-r-0 !bg-background-highlight p-2 !shadow-none hover:!bg-background-low active:!bg-background-low"
+ >
+ -
+
+ zoomIn()}
+ className="rounded-full !border-r-0 !bg-background-highlight p-2 !shadow-none hover:!bg-background-low active:!bg-background-low"
+ >
+ +
+
+
+ )
+ }
+
+ return (
+
+
+
+
+ View the tracks
+
+
+
+
+ {tracks.map(({ key, title, icon }) => (
+
+ {activeSection === key && (
+
+ )}
+ {icon && {icon} }
+ {title}
+
+ ))}
+
+
+
+
+
+ {tracks.map(({ key, icon, contentData }) => {
+ const progressData = progressBar(contentData)
+ return (
+
+
+
+
+
+ {cloneElement(icon as React.ReactElement, {
+ className: "w-8 h-8",
+ style: { overflow: "visible" },
+ })}
+
+
+
{contentData.title}
+
+
+
+
+
Goals:
+
{contentData.goalDescription}
+
+
+
Benefits:
+
+ {contentData.benefits.map((benefit) => (
+
+
+
+ {cloneElement(
+ benefit.icon as React.ReactElement,
+ {
+ className: "w-full h-full",
+ }
+ )}
+
+
+
{benefit.title}
+
+ ))}
+
+
+
+
+
+
+
+ {openItems.includes(key) ? "CLOSE -" : "OPEN +"}
+
+
+
+
+
+
+
+ {progressData.percentage}% completed
+
+
+
+
+
+
+
+ {
+ if (node.type === "group") return
+
+ if (isEqual(node, selectedNode)) {
+ setSelectedNode(null)
+ } else {
+ setSelectedNode({
+ ...node,
+ data: node.data as NodeData,
+ })
+ }
+ }}
+ >
+
+
+
+
+
+ )
+ })}
+
+
+
+ {
+ if (!open) {
+ setSelectedNode(null)
+ }
+ }}
+ >
+
+
+
+
+
+
+ setSelectedNode(null)}
+ >
+
+
+
+
+ {
+ popoverConfig[selectedNode?.type as keyof typeof popoverConfig]
+ ?.pillText
+ }
+
+
+
+ {selectedNode?.data.track}
+
+
{selectedNode?.data.label}
+
+
+ {selectedNode?.data?.description?.map((description) => (
+
+ {description}
+
+ ))}
+
+
+
+
+
+ {popoverConfig[
+ selectedNode?.type as keyof typeof popoverConfig
+ ]?.pillText === "SHIPPED"
+ ? "Shipped:"
+ : "Estimated release:"}
+
+
{selectedNode?.data?.releaseDate}
+
+ {selectedNode?.data?.releaseLabel && (
+
+
Related upgrade:
+
+ {selectedNode?.data?.releaseLabel}
+
+
+ )}
+
+
Benefits:
+
+ {selectedNode?.data?.benefits?.map((benefit) => (
+
+ {benefit}
+
+ ))}
+
+
+
+
Further reading:
+
+ {selectedNode?.data?.furtherReading?.map((reading) => (
+
+ {reading.title}
+
+ ))}
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default RoadmapTracksPage
diff --git a/app/[locale]/roadmap/tracks/_components/useTracks.tsx b/app/[locale]/roadmap/tracks/_components/useTracks.tsx
new file mode 100644
index 00000000000..7564372acea
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/_components/useTracks.tsx
@@ -0,0 +1,163 @@
+import { Edge, Node } from "@xyflow/react"
+
+import {
+ BetterUserExperienceIcon,
+ CheaperTransactionsIcon,
+ EnergyEfficiencyIcon,
+ ExtraSecurityIcon,
+ FutureProofingIcon,
+ GeneralImprovementsIcon,
+ GreenBlockchainIcon,
+ MergeIcon,
+ PurgeIcon,
+ ScourgeIcon,
+ SplurgeIcon,
+ SurgeIcon,
+ VergeIcon,
+} from "@/components/icons/roadmap"
+
+import { mergeEdges, mergeNodes } from "./TrackNodeSetups/MergeTrackNodes"
+import { purgeEdges, purgeNodes } from "./TrackNodeSetups/PurgeTrackNodes"
+import { scourgeEdges, scourgeNodes } from "./TrackNodeSetups/ScourgeTrackNodes"
+import { splurgeEdges, splurgeNodes } from "./TrackNodeSetups/SplurgeTrackNodes"
+import { surgeEdges, surgeNodes } from "./TrackNodeSetups/SurgeTrackNodes"
+import { vergeEdges, vergeNodes } from "./TrackNodeSetups/VergeTrackNodes"
+
+import { useTranslation } from "@/hooks/useTranslation"
+
+type Track = {
+ key: string
+ title: string
+ icon: React.ReactNode
+ contentData: {
+ title: string
+ goalDescription: string
+ benefits: { icon: React.ReactNode; title: string }[]
+ nodes: { nodes: Node[]; edges: Edge[] }
+ }
+}
+
+export const useTracks = (): Track[] => {
+ const { t } = useTranslation("page-roadmap-tracks")
+
+ return [
+ {
+ key: "merge",
+ title: t("page-roadmap-tracks-merge-title"),
+ icon: ,
+ contentData: {
+ title: t("page-roadmap-tracks-merge-content-title"),
+ goalDescription: t("page-roadmap-tracks-merge-goal-description"),
+ benefits: [
+ {
+ icon: ,
+ title: t("page-roadmap-tracks-energy-efficiency"),
+ },
+ {
+ icon: ,
+ title: t("page-roadmap-tracks-green-blockchain"),
+ },
+ ],
+ nodes: {
+ nodes: mergeNodes,
+ edges: mergeEdges,
+ },
+ },
+ },
+ {
+ key: "surge",
+ title: t("page-roadmap-tracks-surge-title"),
+ icon: ,
+ contentData: {
+ title: t("page-roadmap-tracks-surge-content-title"),
+ goalDescription: t("page-roadmap-tracks-surge-goal-description"),
+ benefits: [
+ {
+ icon: ,
+ title: t("page-roadmap-tracks-cheaper-transactions"),
+ },
+ ],
+ nodes: {
+ nodes: surgeNodes,
+ edges: surgeEdges,
+ },
+ },
+ },
+ {
+ key: "scourge",
+ title: t("page-roadmap-tracks-scourge-title"),
+ icon: ,
+ contentData: {
+ title: t("page-roadmap-tracks-scourge-content-title"),
+ goalDescription: t("page-roadmap-tracks-scourge-goal-description"),
+ benefits: [
+ {
+ icon: ,
+ title: t("page-roadmap-tracks-extra-security"),
+ },
+ ],
+ nodes: {
+ nodes: scourgeNodes,
+ edges: scourgeEdges,
+ },
+ },
+ },
+ {
+ key: "purge",
+ title: t("page-roadmap-tracks-purge-title"),
+ icon: ,
+ contentData: {
+ title: t("page-roadmap-tracks-purge-content-title"),
+ goalDescription: t("page-roadmap-tracks-purge-goal-description"),
+ benefits: [
+ {
+ icon: ,
+ title: t("page-roadmap-tracks-future-proofing"),
+ },
+ ],
+ nodes: {
+ nodes: purgeNodes,
+ edges: purgeEdges,
+ },
+ },
+ },
+ {
+ key: "verge",
+ title: t("page-roadmap-tracks-verge-title"),
+ icon: ,
+ contentData: {
+ title: t("page-roadmap-tracks-verge-content-title"),
+ goalDescription: t("page-roadmap-tracks-verge-goal-description"),
+ benefits: [
+ {
+ icon: ,
+ title: t("page-roadmap-tracks-better-user-experience"),
+ },
+ ],
+ nodes: {
+ nodes: vergeNodes,
+ edges: vergeEdges,
+ },
+ },
+ },
+ {
+ key: "splurge",
+ title: t("page-roadmap-tracks-splurge-title"),
+ icon: ,
+ contentData: {
+ title: t("page-roadmap-tracks-splurge-content-title"),
+ goalDescription: t("page-roadmap-tracks-splurge-goal-description"),
+ benefits: [
+ {
+ icon: ,
+ title: t("page-roadmap-tracks-general-improvements"),
+ },
+ ],
+ nodes: {
+ nodes: splurgeNodes,
+ edges: splurgeEdges,
+ },
+ },
+ },
+ ]
+}
diff --git a/app/[locale]/roadmap/tracks/page.tsx b/app/[locale]/roadmap/tracks/page.tsx
new file mode 100644
index 00000000000..9cd112ffd57
--- /dev/null
+++ b/app/[locale]/roadmap/tracks/page.tsx
@@ -0,0 +1,48 @@
+import pick from "lodash.pick"
+import { getTranslations } from "next-intl/server"
+
+import { Lang } from "@/lib/types"
+
+import I18nProvider from "@/components/I18nProvider"
+
+import { getMetadata } from "@/lib/utils/metadata"
+import { getRequiredNamespacesForPage } from "@/lib/utils/translations"
+
+import RoadmapTracksPage from "./_components/tracks"
+
+import { loadMessages } from "@/i18n/loadMessages"
+
+const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => {
+ const { locale } = await params
+
+ // Get i18n messages
+ const allMessages = await loadMessages(locale)
+ const requiredNamespaces = getRequiredNamespacesForPage("/roadmap/tracks")
+ const messages = pick(allMessages, requiredNamespaces)
+
+ return (
+
+
+
+ )
+}
+
+export async function generateMetadata({
+ params,
+}: {
+ params: Promise<{ locale: string }>
+}) {
+ const { locale } = await params
+
+ const t = await getTranslations({ locale, namespace: "page-roadmap-tracks" })
+
+ return await getMetadata({
+ locale,
+ slug: ["roadmap/tracks"],
+ title: t("page-roadmap-tracks-meta-title"),
+ description: t("page-roadmap-tracks-meta-description"),
+ image: "/images/roadmap/roadmap-tracks-hero.png",
+ })
+}
+
+export default Page
diff --git a/package.json b/package.json
index 15a66c9a9bb..ac32515e071 100644
--- a/package.json
+++ b/package.json
@@ -51,6 +51,7 @@
"@socialgouv/matomo-next": "^1.8.0",
"@tanstack/react-query": "^5.66.7",
"@tanstack/react-table": "^8.19.3",
+ "@xyflow/react": "^12.6.0",
"chart.js": "^4.4.2",
"chartjs-plugin-datalabels": "^2.2.0",
"class-variance-authority": "^0.7.0",
diff --git a/public/images/roadmap/roadmap-tracks-hero.png b/public/images/roadmap/roadmap-tracks-hero.png
new file mode 100644
index 00000000000..4066b6138bf
Binary files /dev/null and b/public/images/roadmap/roadmap-tracks-hero.png differ
diff --git a/public/images/roadmap/roadmap-tracks-image.png b/public/images/roadmap/roadmap-tracks-image.png
new file mode 100644
index 00000000000..507c5f3c12e
Binary files /dev/null and b/public/images/roadmap/roadmap-tracks-image.png differ
diff --git a/src/components/Nav/useNav.ts b/src/components/Nav/useNav.ts
index d611c109fe8..43c51e09fc7 100644
--- a/src/components/Nav/useNav.ts
+++ b/src/components/Nav/useNav.ts
@@ -427,6 +427,11 @@ export const useNav = () => {
description: t("nav-roadmap-overview-description"),
href: "/roadmap/",
},
+ {
+ label: t("nav-roadmap-tracks-label"),
+ description: t("nav-roadmap-tracks-description"),
+ href: "/roadmap/tracks/",
+ },
{
label: t("nav-roadmap-security-label"),
description: t("nav-roadmap-security-description"),
diff --git a/src/components/icons/roadmap/BetterUserExperienceIcon.tsx b/src/components/icons/roadmap/BetterUserExperienceIcon.tsx
index dde3eb9af99..fb5647983d1 100644
--- a/src/components/icons/roadmap/BetterUserExperienceIcon.tsx
+++ b/src/components/icons/roadmap/BetterUserExperienceIcon.tsx
@@ -8,15 +8,15 @@ export const BetterUserExperienceIcon = createIconBase({
<>
+
+ >
+ ),
+})
diff --git a/src/components/icons/roadmap/ExtraSecurityIcon.tsx b/src/components/icons/roadmap/ExtraSecurityIcon.tsx
index 7b304aeae4e..65a3480a27d 100644
--- a/src/components/icons/roadmap/ExtraSecurityIcon.tsx
+++ b/src/components/icons/roadmap/ExtraSecurityIcon.tsx
@@ -8,15 +8,15 @@ export const ExtraSecurityIcon = createIconBase({
<>
>
),
diff --git a/src/components/icons/roadmap/FutureProofingIcon.tsx b/src/components/icons/roadmap/FutureProofingIcon.tsx
index cfbe18c7b30..2cd38a8d23a 100644
--- a/src/components/icons/roadmap/FutureProofingIcon.tsx
+++ b/src/components/icons/roadmap/FutureProofingIcon.tsx
@@ -8,19 +8,19 @@ export const FutureProofingIcon = createIconBase({
<>
+
+ >
+ ),
+})
diff --git a/src/components/icons/roadmap/GreenBlockchainIcon.tsx b/src/components/icons/roadmap/GreenBlockchainIcon.tsx
new file mode 100644
index 00000000000..0da54e35138
--- /dev/null
+++ b/src/components/icons/roadmap/GreenBlockchainIcon.tsx
@@ -0,0 +1,15 @@
+import { createIconBase } from "../icon-base"
+
+export const GreenBlockchainIcon = createIconBase({
+ displayName: "GreenBlockchainIcon",
+ viewBox: "0 0 15 15",
+ className: "w-[15px] h-[15px]",
+ children: (
+ <>
+
+ >
+ ),
+})
diff --git a/src/components/icons/roadmap/MergeIcon.tsx b/src/components/icons/roadmap/MergeIcon.tsx
new file mode 100644
index 00000000000..eb112f91ba4
--- /dev/null
+++ b/src/components/icons/roadmap/MergeIcon.tsx
@@ -0,0 +1,15 @@
+import { createIconBase } from "../icon-base"
+
+export const MergeIcon = createIconBase({
+ displayName: "MergeIcon",
+ viewBox: "0 0 17 17",
+ className: "w-[17px] h-[17px]",
+ children: (
+ <>
+
+ >
+ ),
+})
diff --git a/src/components/icons/roadmap/PurgeIcon.tsx b/src/components/icons/roadmap/PurgeIcon.tsx
new file mode 100644
index 00000000000..ca6c67ae420
--- /dev/null
+++ b/src/components/icons/roadmap/PurgeIcon.tsx
@@ -0,0 +1,15 @@
+import { createIconBase } from "../icon-base"
+
+export const PurgeIcon = createIconBase({
+ displayName: "PurgeIcon",
+ viewBox: "0 0 17 17",
+ className: "w-[17px] h-[17px]",
+ children: (
+ <>
+
+ >
+ ),
+})
diff --git a/src/components/icons/roadmap/ScourgeIcon.tsx b/src/components/icons/roadmap/ScourgeIcon.tsx
new file mode 100644
index 00000000000..0195aa25b5e
--- /dev/null
+++ b/src/components/icons/roadmap/ScourgeIcon.tsx
@@ -0,0 +1,15 @@
+import { createIconBase } from "../icon-base"
+
+export const ScourgeIcon = createIconBase({
+ displayName: "ScourgeIcon",
+ viewBox: "0 0 17 17",
+ className: "w-[17px] h-[17px]",
+ children: (
+ <>
+
+ >
+ ),
+})
diff --git a/src/components/icons/roadmap/SplurgeIcon.tsx b/src/components/icons/roadmap/SplurgeIcon.tsx
new file mode 100644
index 00000000000..790ec3c0203
--- /dev/null
+++ b/src/components/icons/roadmap/SplurgeIcon.tsx
@@ -0,0 +1,15 @@
+import { createIconBase } from "../icon-base"
+
+export const SplurgeIcon = createIconBase({
+ displayName: "SplurgeIcon",
+ viewBox: "0 0 17 17",
+ className: "w-[17px] h-[17px]",
+ children: (
+ <>
+
+ >
+ ),
+})
diff --git a/src/components/icons/roadmap/StakingWithdrawalsIcon.tsx b/src/components/icons/roadmap/StakingWithdrawalsIcon.tsx
index 2023033b85f..a36a615b807 100644
--- a/src/components/icons/roadmap/StakingWithdrawalsIcon.tsx
+++ b/src/components/icons/roadmap/StakingWithdrawalsIcon.tsx
@@ -8,7 +8,7 @@ export const StakingWithdrawalsIcon = createIconBase({
<>
>
),
diff --git a/src/components/icons/roadmap/SurgeIcon.tsx b/src/components/icons/roadmap/SurgeIcon.tsx
new file mode 100644
index 00000000000..38fdc868c17
--- /dev/null
+++ b/src/components/icons/roadmap/SurgeIcon.tsx
@@ -0,0 +1,15 @@
+import { createIconBase } from "../icon-base"
+
+export const SurgeIcon = createIconBase({
+ displayName: "SurgeIcon",
+ viewBox: "0 0 17 17",
+ className: "w-[17px] h-[17px]",
+ children: (
+ <>
+
+ >
+ ),
+})
diff --git a/src/components/icons/roadmap/VergeIcon.tsx b/src/components/icons/roadmap/VergeIcon.tsx
new file mode 100644
index 00000000000..ee4dc71f380
--- /dev/null
+++ b/src/components/icons/roadmap/VergeIcon.tsx
@@ -0,0 +1,15 @@
+import { createIconBase } from "../icon-base"
+
+export const VergeIcon = createIconBase({
+ displayName: "VergeIcon",
+ viewBox: "0 0 17 17",
+ className: "w-[17px] h-[17px]",
+ children: (
+ <>
+
+ >
+ ),
+})
diff --git a/src/components/icons/roadmap/index.ts b/src/components/icons/roadmap/index.ts
index 5beac56b0b2..0f84e8260c0 100644
--- a/src/components/icons/roadmap/index.ts
+++ b/src/components/icons/roadmap/index.ts
@@ -2,13 +2,22 @@ import { AccountAbstractionIcon } from "./AccountAbstractionIcon"
import { BetterUserExperienceIcon } from "./BetterUserExperienceIcon"
import { CheaperTransactionsIcon } from "./CheaperTransactionsIcon"
import { DankshardingIcon } from "./DankshardingIcon"
+import { EnergyEfficiencyIcon } from "./EnergyEfficiencyIcon"
import { ExtraSecurityIcon } from "./ExtraSecurityIcon"
import { FutureProofingIcon } from "./FutureProofingIcon"
+import { GeneralImprovementsIcon } from "./GeneralImprovementsIcon"
+import { GreenBlockchainIcon } from "./GreenBlockchainIcon"
+import { MergeIcon } from "./MergeIcon"
import { ProposerBuilderSeparationIcon } from "./ProposerBuilderSeparationIcon"
+import { PurgeIcon } from "./PurgeIcon"
+import { ScourgeIcon } from "./ScourgeIcon"
import { SecretLeaderElectionIcon } from "./SecretLeaderElectionIcon"
import { SingleSlotFinalityIcon } from "./SingleSlotFinalityIcon"
+import { SplurgeIcon } from "./SplurgeIcon"
import { StakingWithdrawalsIcon } from "./StakingWithdrawalsIcon"
import { StatelessnessIcon } from "./StatelessnessIcon"
+import { SurgeIcon } from "./SurgeIcon"
+import { VergeIcon } from "./VergeIcon"
import { VerkleTreesIcon } from "./VerkleTreesIcon"
export {
@@ -16,12 +25,21 @@ export {
BetterUserExperienceIcon,
CheaperTransactionsIcon,
DankshardingIcon,
+ EnergyEfficiencyIcon,
ExtraSecurityIcon,
FutureProofingIcon,
+ GeneralImprovementsIcon,
+ GreenBlockchainIcon,
+ MergeIcon,
ProposerBuilderSeparationIcon,
+ PurgeIcon,
+ ScourgeIcon,
SecretLeaderElectionIcon,
SingleSlotFinalityIcon,
+ SplurgeIcon,
StakingWithdrawalsIcon,
StatelessnessIcon,
+ SurgeIcon,
+ VergeIcon,
VerkleTreesIcon,
}
diff --git a/src/components/ui/accordion.tsx b/src/components/ui/accordion.tsx
index c81d7d2c305..e284379f1bb 100644
--- a/src/components/ui/accordion.tsx
+++ b/src/components/ui/accordion.tsx
@@ -21,7 +21,7 @@ const AccordionTrigger = React.forwardRef<
hideIcon?: boolean
}
>(({ className, children, hideIcon = false, ...props }, ref) => (
-
+
(({ className, children, ...props }, ref) => (
{children}
diff --git a/src/data/roadmap/releases.tsx b/src/data/roadmap/releases.tsx
index 571ce583f48..38a55714d82 100644
--- a/src/data/roadmap/releases.tsx
+++ b/src/data/roadmap/releases.tsx
@@ -6,6 +6,7 @@ import GuidesHubHeroImage from "@/public/images/heroes/guides-hub-hero.jpg"
import Layer2HubHeroImage from "@/public/images/heroes/layer-2-hub-hero.jpg"
import QuizzesHubHeroImage from "@/public/images/heroes/quizzes-hub-hero.png"
import PectraImage from "@/public/images/roadmap/roadmap-pectra.png"
+import RoadmapNodeImage from "@/public/images/roadmap/roadmap-tracks-image.png"
interface Release {
image: StaticImageData
@@ -114,11 +115,14 @@ export const releasesData: Release[] = [
releaseDate: "2025-05-07",
content: (
-
Enhance EOA wallets with smart contract functionality
+
+ Enhance EOA wallets with smart contract functionality
+
Users can set their address to be represented by a code of an
- existing smart contract and gain benefits such as transaction batching, transaction fee sponsorship or better recovery mechanisms
+ existing smart contract and gain benefits such as transaction
+ batching, transaction fee sponsorship or better recovery mechanisms
Increase the max effective balance
@@ -184,3 +188,23 @@ export const releasesData: Release[] = [
href: "https://eips.ethereum.org/EIPS/eip-7773",
},
]
+
+// TODO: Add future releases when implementing /roadmap/tracks
+const futureRelease: Release = {
+ image: RoadmapNodeImage,
+ releaseName: "Future releases",
+ releaseDate: "Future",
+ content: (
+
+
+ Ethereum's roadmap continues to be developed, with more to come!
+
+
+ ),
+ href: "/roadmap/tracks",
+}
+
+export const releasesDataWithFuture: Release[] = [
+ ...releasesData,
+ futureRelease,
+]
diff --git a/src/intl/en/common.json b/src/intl/en/common.json
index 4d304eacd50..fc994b6f749 100644
--- a/src/intl/en/common.json
+++ b/src/intl/en/common.json
@@ -311,6 +311,8 @@
"nav-roadmap-options": "Roadmap Options",
"nav-roadmap-options-alt": "Roadmap options dropdown menu",
"nav-roadmap-overview-description": "The future of Ethereum",
+ "nav-roadmap-tracks-label": "Roadmap tracks",
+ "nav-roadmap-tracks-description": "Visualize Ethereum's roadmap in a more detailed way",
"nav-roadmap-scaling": "Scaling",
"nav-roadmap-scaling-description": "Network updates to further reduce transaction costs and speed",
"nav-roadmap-scaling-label": "Cheaper transactions",
diff --git a/src/intl/en/page-roadmap-tracks.json b/src/intl/en/page-roadmap-tracks.json
new file mode 100644
index 00000000000..4900bdb8667
--- /dev/null
+++ b/src/intl/en/page-roadmap-tracks.json
@@ -0,0 +1,30 @@
+{
+ "page-roadmap-tracks-meta-title": "Ethereum roadmap tracks",
+ "page-roadmap-tracks-meta-description": "The Ethereum roadmap, like Ethereum itself, doesn't have a single person or group in charge. One interpretation comes from Ethereum co-founder Vitalik Buterin's 2022 vision, with development shaped by contributions from across the Ethereum community.",
+ "page-roadmap-tracks-whats-on-this-page": "What's on this page",
+ "page-roadmap-tracks-merge-title": "Merge",
+ "page-roadmap-tracks-surge-title": "Surge",
+ "page-roadmap-tracks-scourge-title": "Scourge",
+ "page-roadmap-tracks-purge-title": "Purge",
+ "page-roadmap-tracks-verge-title": "Verge",
+ "page-roadmap-tracks-splurge-title": "Splurge",
+ "page-roadmap-tracks-merge-content-title": "The Merge",
+ "page-roadmap-tracks-merge-goal-description": "Join the old Ethereum system with the new energy-efficient one, while making Ethereum greener and ready for future upgrades.",
+ "page-roadmap-tracks-surge-content-title": "The Surge",
+ "page-roadmap-tracks-surge-goal-description": "Make Ethereum faster and cheaper to use by introducing ways to handle lots of transactions at once (using rollups and sharding).",
+ "page-roadmap-tracks-scourge-content-title": "The Scourge",
+ "page-roadmap-tracks-scourge-goal-description": "Keep Ethereum fair by stopping big groups or companies from controlling how transactions are processed or prioritised.",
+ "page-roadmap-tracks-purge-content-title": "The Purge",
+ "page-roadmap-tracks-purge-goal-description": "Get rid of unnecessary data and history on the network to keep Ethereum efficient and manageable over time.",
+ "page-roadmap-tracks-verge-content-title": "The Verge",
+ "page-roadmap-tracks-verge-goal-description": "Make Ethereum easier to use and run by simplifying how data is stored and processed, so more users can participate in securing the network.",
+ "page-roadmap-tracks-splurge-content-title": "The Splurge",
+ "page-roadmap-tracks-splurge-goal-description": "Add extra features and upgrades to make Ethereum as smooth, user-friendly, and powerful as possible.",
+ "page-roadmap-tracks-energy-efficiency": "Energy efficiency",
+ "page-roadmap-tracks-green-blockchain": "Green blockchain",
+ "page-roadmap-tracks-cheaper-transactions": "Cheaper transactions",
+ "page-roadmap-tracks-extra-security": "Extra security",
+ "page-roadmap-tracks-future-proofing": "Future-proofing",
+ "page-roadmap-tracks-better-user-experience": "Better user experience",
+ "page-roadmap-tracks-general-improvements": "General improvements"
+}
diff --git a/src/lib/utils/translations.ts b/src/lib/utils/translations.ts
index 6825585afcd..f7b6c9ffdff 100644
--- a/src/lib/utils/translations.ts
+++ b/src/lib/utils/translations.ts
@@ -191,6 +191,10 @@ const getRequiredNamespacesForPath = (relativePath: string) => {
primaryNamespace = "page-roadmap"
}
+ if (path.startsWith("/roadmap/tracks/")) {
+ primaryNamespace = "page-roadmap-tracks"
+ }
+
if (path.startsWith("/start/")) {
requiredNamespaces = [...requiredNamespaces]
}
diff --git a/yarn.lock b/yarn.lock
index 0a2535d4268..811a4481ddc 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5057,12 +5057,19 @@
resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-3.1.3.tgz#368c961a18de721da8200e80bf3943fb53136af2"
integrity sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==
+"@types/d3-drag@^3.0.7":
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/@types/d3-drag/-/d3-drag-3.0.7.tgz#b13aba8b2442b4068c9a9e6d1d82f8bcea77fc02"
+ integrity sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==
+ dependencies:
+ "@types/d3-selection" "*"
+
"@types/d3-ease@^3.0.0":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@types/d3-ease/-/d3-ease-3.0.2.tgz#e28db1bfbfa617076f7770dd1d9a48eaa3b6c51b"
integrity sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==
-"@types/d3-interpolate@^3.0.1":
+"@types/d3-interpolate@*", "@types/d3-interpolate@^3.0.1":
version "3.0.4"
resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz#412b90e84870285f2ff8a846c6eb60344f12a41c"
integrity sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==
@@ -5081,6 +5088,11 @@
dependencies:
"@types/d3-time" "*"
+"@types/d3-selection@*", "@types/d3-selection@^3.0.10":
+ version "3.0.11"
+ resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-3.0.11.tgz#bd7a45fc0a8c3167a631675e61bc2ca2b058d4a3"
+ integrity sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==
+
"@types/d3-shape@^3.1.0":
version "3.1.6"
resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-3.1.6.tgz#65d40d5a548f0a023821773e39012805e6e31a72"
@@ -5098,6 +5110,21 @@
resolved "https://registry.yarnpkg.com/@types/d3-timer/-/d3-timer-3.0.2.tgz#70bbda77dc23aa727413e22e214afa3f0e852f70"
integrity sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==
+"@types/d3-transition@^3.0.8":
+ version "3.0.9"
+ resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-3.0.9.tgz#1136bc57e9ddb3c390dccc9b5ff3b7d2b8d94706"
+ integrity sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==
+ dependencies:
+ "@types/d3-selection" "*"
+
+"@types/d3-zoom@^3.0.8":
+ version "3.0.8"
+ resolved "https://registry.yarnpkg.com/@types/d3-zoom/-/d3-zoom-3.0.8.tgz#dccb32d1c56b1e1c6e0f1180d994896f038bc40b"
+ integrity sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==
+ dependencies:
+ "@types/d3-interpolate" "*"
+ "@types/d3-selection" "*"
+
"@types/debug@^4.0.0", "@types/debug@^4.1.7":
version "4.1.12"
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917"
@@ -6097,6 +6124,28 @@
resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
+"@xyflow/react@^12.6.0":
+ version "12.6.0"
+ resolved "https://registry.yarnpkg.com/@xyflow/react/-/react-12.6.0.tgz#df02d2f5b701739c14387d8f608182e67b7774e5"
+ integrity sha512-YzsSK4SlpC6e9Ki1g6O9B1UH7xvz/bzWF+tJ+vWDD8Am5xJmFn0jYnCEuqvzvH8dRKb1NFBmyuqEGqWN39xXsA==
+ dependencies:
+ "@xyflow/system" "0.0.57"
+ classcat "^5.0.3"
+ zustand "^4.4.0"
+
+"@xyflow/system@0.0.57":
+ version "0.0.57"
+ resolved "https://registry.yarnpkg.com/@xyflow/system/-/system-0.0.57.tgz#5e3980136b02f281b1c5962d6ae6792e524006c7"
+ integrity sha512-1YpBo0WgmZLR5wQw9Jvk3Tu0gISi/oYc4uSimrDuAsA/G2rGleulLrKkM59uuT/QU5m6DYC2VdBDAzjSNMGuBA==
+ 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"
+
"@yarnpkg/esbuild-plugin-pnp@^3.0.0-rc.10":
version "3.0.0-rc.15"
resolved "https://registry.yarnpkg.com/@yarnpkg/esbuild-plugin-pnp/-/esbuild-plugin-pnp-3.0.0-rc.15.tgz#4e40e7d2eb28825c9a35ab9d04c363931d7c0e67"
@@ -7215,6 +7264,11 @@ class-variance-authority@^0.7.0:
dependencies:
clsx "2.0.0"
+classcat@^5.0.3:
+ version "5.0.5"
+ resolved "https://registry.yarnpkg.com/classcat/-/classcat-5.0.5.tgz#8c209f359a93ac302404a10161b501eba9c09c77"
+ integrity sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==
+
classnames@^2.2.5:
version "2.5.1"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b"
@@ -7743,7 +7797,20 @@ csstype@^3.0.2, csstype@^3.0.7:
resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2"
integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==
-d3-ease@^3.0.1:
+"d3-dispatch@1 - 3":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz#5fc75284e9c2375c36c839411a0cf550cbfc4d5e"
+ integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==
+
+"d3-drag@2 - 3", d3-drag@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-3.0.0.tgz#994aae9cd23c719f53b5e10e3a0a6108c69607ba"
+ integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==
+ dependencies:
+ d3-dispatch "1 - 3"
+ d3-selection "3"
+
+"d3-ease@1 - 3", d3-ease@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4"
integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==
@@ -7753,7 +7820,7 @@ d3-ease@^3.0.1:
resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641"
integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==
-"d3-interpolate@1.2.0 - 3", d3-interpolate@^3.0.1:
+"d3-interpolate@1 - 3", "d3-interpolate@1.2.0 - 3", d3-interpolate@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d"
integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==
@@ -7776,6 +7843,11 @@ d3-scale@^4.0.2:
d3-time "2.1.1 - 3"
d3-time-format "2 - 4"
+"d3-selection@2 - 3", d3-selection@3, d3-selection@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-3.0.0.tgz#c25338207efa72cc5b9bd1458a1a41901f1e1b31"
+ integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==
+
d3-shape@^3.1.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-3.2.0.tgz#a1a839cbd9ba45f28674c69d7f855bcf91dfc6a5"
@@ -7797,11 +7869,33 @@ d3-shape@^3.1.0:
dependencies:
d3-array "2 - 3"
-d3-timer@^3.0.1:
+"d3-timer@1 - 3", d3-timer@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0"
integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==
+"d3-transition@2 - 3":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-3.0.1.tgz#6869fdde1448868077fdd5989200cb61b2a1645f"
+ integrity sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==
+ dependencies:
+ d3-color "1 - 3"
+ d3-dispatch "1 - 3"
+ d3-ease "1 - 3"
+ d3-interpolate "1 - 3"
+ d3-timer "1 - 3"
+
+d3-zoom@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-3.0.0.tgz#d13f4165c73217ffeaa54295cd6969b3e7aee8f3"
+ integrity sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==
+ dependencies:
+ d3-dispatch "1 - 3"
+ d3-drag "2 - 3"
+ d3-interpolate "1 - 3"
+ d3-selection "2 - 3"
+ d3-transition "2 - 3"
+
damerau-levenshtein@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
@@ -15597,6 +15691,11 @@ use-sync-external-store@1.4.0:
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz#adbc795d8eeb47029963016cefdf89dc799fcebc"
integrity sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==
+use-sync-external-store@^1.2.2:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz#55122e2a3edd2a6c106174c27485e0fd59bcfca0"
+ integrity sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==
+
usehooks-ts@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/usehooks-ts/-/usehooks-ts-3.1.0.tgz#156119f36efc85f1b1952616c02580f140950eca"
@@ -16129,6 +16228,13 @@ zustand@5.0.0:
resolved "https://registry.yarnpkg.com/zustand/-/zustand-5.0.0.tgz#71f8aaecf185592a3ba2743d7516607361899da9"
integrity sha512-LE+VcmbartOPM+auOjCCLQOsQ05zUTp8RkgwRzefUk+2jISdMMFnxvyTjA4YNWr5ZGXYbVsEMZosttuxUBkojQ==
+zustand@^4.4.0:
+ version "4.5.6"
+ resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.5.6.tgz#6857d52af44874a79fb3408c9473f78367255c96"
+ integrity sha512-ibr/n1hBzLLj5Y+yUcU7dYw8p6WnIVzdJbnX+1YpaScvZVF2ziugqHs+LAmHw4lWO9c/zRj+K1ncgWDQuthEdQ==
+ dependencies:
+ use-sync-external-store "^1.2.2"
+
zwitch@^2.0.0:
version "2.0.4"
resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7"