+ {parts.map((part, i) => {
+ // Title handling
+ if (part.startsWith('# ')) {
+ return (
+
+ {part.substring(2)}
+
+ );
+ }
+
+ // Code block handling
+ if (part.startsWith('```')) {
+ const codeLines = part.split('\n');
+ // Extract language from the first line, e.g. ```solidity => solidity
+ const languageMatch = codeLines[0].match(/^```(\w+)$/);
+ // Default to javascript if no language is specified
+ const language = languageMatch ? languageMatch[1] : 'javascript';
+ const codeContent = codeLines.slice(1, -1).join('\n');
+
+ return (
+
+
+ {codeContent}
+
+
+ );
+ }
+
+ // List handling
+ if (part.includes('\n1. ')) {
+ const items = part.split('\n').filter((line) => line.match(/^\d+\./));
+ return (
+
+ {items.map((item, j) => {
+ const content = item.replace(/^\d+\.\s+/, '');
+ // Check if the content contains inline code
+ const formattedContent = content.replace(
+ /`([^`]+)`/g,
+ (_, code) =>
+ `${code}`,
+ );
+
+ return (
+
+ );
+ })}
+
+ );
+ }
+
+ // Regular paragraph with link and inline code handling
+ let processedContent = part;
+
+ // Handle inline code
+ processedContent = processedContent.replace(
+ /`([^`]+)`/g,
+ (_, code) =>
+ `
${code}`,
+ );
+
+ // Handle links [text](url)
+ processedContent = processedContent.replace(
+ /\[([^\]]+)\]\(([^)]+)\)/g,
+ (_, text, url) =>
+ `
${text}`,
+ );
+
+ return (
+
+ );
+ })}
+
+ );
+}
diff --git a/website/src/components/InteractiveDiagrams/modals-as-pages-plugin/registry.js b/website/src/components/InteractiveDiagrams/modals-as-pages-plugin/registry.js
new file mode 100644
index 0000000000..2d91e1e411
--- /dev/null
+++ b/website/src/components/InteractiveDiagrams/modals-as-pages-plugin/registry.js
@@ -0,0 +1,83 @@
+/**
+ * Registry utility functions for the modals-as-pages plugin.
+ * Provides helper functions to work with the content registry.
+ */
+
+import { usePluginData } from '@docusaurus/useGlobalData';
+
+/**
+ * Hook to access the content registry from the modals-as-pages plugin.
+ *
+ * @returns {Object} The content registry object
+ */
+export function useContentRegistry() {
+ const { contentRegistry = {} } = usePluginData('modals-as-pages-plugin') || {};
+ return contentRegistry;
+}
+
+/**
+ * Hook to get content for a specific context, group, and content ID.
+ *
+ * @param {string} contextId The context identifier (e.g., 'diagrams', 'tutorials')
+ * @param {string} groupId The group identifier (e.g., 'transaction-flow', 'getting-started')
+ * @param {string} contentId The content identifier (e.g., 'step-1', 'welcome')
+ * @returns {Object|null} The content object or null if not found
+ */
+export function useContent(contextId, groupId, contentId) {
+ const contentRegistry = useContentRegistry();
+ return contentRegistry[contextId]?.[groupId]?.[contentId] || null;
+}
+
+/**
+ * Hook to get all available group IDs for a specific context.
+ *
+ * @param {string} contextId The context identifier
+ * @returns {string[]} Array of available group IDs
+ */
+export function useAvailableGroups(contextId) {
+ const contentRegistry = useContentRegistry();
+ return contentRegistry[contextId] ? Object.keys(contentRegistry[contextId]) : [];
+}
+
+/**
+ * Hook to get all available content IDs for a specific context and group.
+ *
+ * @param {string} contextId The context identifier
+ * @param {string} groupId The group identifier
+ * @returns {string[]} Array of available content IDs
+ */
+export function useAvailableContent(contextId, groupId) {
+ const contentRegistry = useContentRegistry();
+ return contentRegistry[contextId]?.[groupId]
+ ? Object.keys(contentRegistry[contextId][groupId])
+ : [];
+}
+
+/**
+ * Hook to check if content exists for a specific context, group, and content ID.
+ *
+ * @param {string} contextId The context identifier
+ * @param {string} groupId The group identifier
+ * @param {string} contentId The content identifier
+ * @returns {boolean} True if the content exists, false otherwise
+ */
+export function useContentExists(contextId, groupId, contentId) {
+ const contentRegistry = useContentRegistry();
+ return Boolean(contentRegistry[contextId]?.[groupId]?.[contentId]);
+}
+
+/**
+ * Helper for mapping diagram ID and step number to content parameters.
+ * Useful for compatibility with existing diagram components.
+ *
+ * @param {string} diagramId The diagram identifier
+ * @param {number|string} stepNumber The step number
+ * @returns {Object} Object with contextId, groupId, and contentId
+ */
+export function getDiagramContentParams(diagramId, stepNumber) {
+ return {
+ contextId: 'diagrams',
+ groupId: diagramId,
+ contentId: `step-${stepNumber}`,
+ };
+}
diff --git a/website/src/components/InteractiveDiagrams/modals-as-pages-plugin/types.ts b/website/src/components/InteractiveDiagrams/modals-as-pages-plugin/types.ts
new file mode 100644
index 0000000000..07db30fc5c
--- /dev/null
+++ b/website/src/components/InteractiveDiagrams/modals-as-pages-plugin/types.ts
@@ -0,0 +1,141 @@
+/**
+ * Type definitions for the modals-as-pages plugin.
+ */
+
+import React from 'react';
+
+/**
+ * Plugin options interface.
+ */
+export interface ModalsAsPagesPluginOptions {
+ /**
+ * Directory or directories containing the content files.
+ * Can be a single string or an array of strings.
+ */
+ contentDir: string | string[];
+
+ /**
+ * Glob pattern to match content files.
+ * Default: '**\/*.mdx'
+ */
+ filePattern?: string;
+
+ /**
+ * Function to generate content identifiers from a file path.
+ * @param filePath Relative path to the content file
+ * @returns Object with contextId, groupId, and contentId
+ */
+ contentIdGenerator?: (filePath: string) => ContentIdentifiers;
+
+ /**
+ * Array of content transformer functions.
+ * Each transformer receives the content and metadata and returns transformed content.
+ */
+ transformers?: ContentTransformer[];
+}
+
+/**
+ * Content identifiers object.
+ */
+export interface ContentIdentifiers {
+ /**
+ * Top-level context identifier (e.g., 'diagrams', 'tutorials').
+ */
+ contextId: string;
+
+ /**
+ * Group identifier within the context (e.g., 'transaction-flow', 'getting-started').
+ */
+ groupId: string;
+
+ /**
+ * Content identifier within the group (e.g., 'step-1', 'welcome').
+ */
+ contentId: string;
+}
+
+/**
+ * Content transformer function type.
+ */
+export type ContentTransformer = (content: string, metadata: ContentIdentifiers) => string;
+
+/**
+ * Content entry in the registry.
+ */
+export interface ContentEntry {
+ /**
+ * Relative path to the content file.
+ */
+ relativePath: string;
+
+ /**
+ * The content text (possibly transformed).
+ */
+ content: string;
+}
+
+/**
+ * Content registry structure.
+ */
+export interface ContentRegistry {
+ [contextId: string]: {
+ [groupId: string]: {
+ [contentId: string]: ContentEntry;
+ };
+ };
+}
+
+/**
+ * Props for the ModalContentLoader component.
+ */
+export interface ModalContentLoaderProps {
+ /**
+ * The context identifier.
+ */
+ contextId: string;
+
+ /**
+ * The group identifier.
+ */
+ groupId: string;
+
+ /**
+ * The content identifier.
+ */
+ contentId: string;
+
+ /**
+ * Optional fallback content to display if the requested content is not found.
+ */
+ fallback?: React.ReactNode;
+
+ /**
+ * Optional CSS class name for the content container.
+ */
+ className?: string;
+}
+
+/**
+ * Props for the legacy DiagramContentLoader component.
+ */
+export interface DiagramContentLoaderProps {
+ /**
+ * The diagram identifier.
+ */
+ diagramId: string;
+
+ /**
+ * The step number.
+ */
+ stepNumber: number | string;
+
+ /**
+ * Optional fallback content.
+ */
+ fallback?: React.ReactNode;
+
+ /**
+ * Optional CSS class name.
+ */
+ className?: string;
+}
diff --git a/website/src/css/custom.css b/website/src/css/custom.css
index 6795efc279..9237a3a05c 100644
--- a/website/src/css/custom.css
+++ b/website/src/css/custom.css
@@ -77,3 +77,16 @@
.img-500px { width: 500px; }
.img-600px { width: 600px; }
.img-900px { width: 900px; }
+
+/* Animation for interactive buttons */
+@keyframes blink {
+ 0% { opacity: 0.8; }
+ 50% { opacity: 1; }
+ 100% { opacity: 0.8; }
+}
+
+.interactive-button-circle {
+ fill: #ff7f2a;
+ transition: filter 0.2s;
+ animation: blink 2s ease-in-out infinite;
+}
diff --git a/website/static/img/timeboost-centralized-timeboost-auction-workflow.jpg b/website/static/img/timeboost-centralized-timeboost-auction-workflow.jpg
deleted file mode 100644
index 5dc6457bc7..0000000000
Binary files a/website/static/img/timeboost-centralized-timeboost-auction-workflow.jpg and /dev/null differ
diff --git a/website/static/img/timeboost-centralized-timeboost-auction-workflow.svg b/website/static/img/timeboost-centralized-timeboost-auction-workflow.svg
new file mode 100644
index 0000000000..2d04fc967f
--- /dev/null
+++ b/website/static/img/timeboost-centralized-timeboost-auction-workflow.svg
@@ -0,0 +1,3056 @@
+
+