diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 000000000..429e43e56
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,126 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+
+## Repository Overview
+This is the Optimism Documentation website repository that powers docs.optimism.io - the official technical documentation for the Optimism Collective, covering the OP Stack, Superchain, and interoperability features.
+
+## Tech Stack
+- **Framework**: Next.js 14.2.21 with React 18.2.0
+- **Documentation Engine**: Nextra 2.13.2 (docs theme)
+- **Language**: TypeScript
+- **Package Manager**: pnpm (required - do not use npm or yarn)
+- **Content Format**: MDX (Markdown with React components)
+- **Deployment**: Netlify
+
+## Essential Commands
+
+### Development
+```bash
+pnpm dev # Start development server at localhost:3001
+pnpm build # Create production build
+```
+
+### Quality Checks (Run before committing)
+```bash
+pnpm lint # Run all linting (ESLint + spellcheck + breadcrumbs + redirects + metadata)
+pnpm fix # Auto-fix all fixable issues (runs on pre-push automatically)
+```
+
+### Individual Linting Commands
+```bash
+pnpm spellcheck:lint # Check spelling
+pnpm spellcheck:fix # Add words to dictionary (words.txt)
+pnpm lint:eslint # Run ESLint
+pnpm lint:breadcrumbs # Validate breadcrumb structure
+pnpm lint:redirects # Check redirect configuration
+pnpm lint:metadata # Validate page metadata
+```
+
+## Architecture & Structure
+
+### Content Organization
+```
+pages/ # All documentation content (MDX files)
+├── app-developers/ # Application developer guides
+├── operators/ # Node & chain operator documentation
+├── stack/ # OP Stack protocol documentation
+├── superchain/ # Superchain network documentation
+├── interop/ # Interoperability documentation
+└── connect/ # Contributing guides and resources
+```
+
+### Key Directories
+- `components/`: Reusable React components for documentation
+- `public/`: Static assets, images, and tutorial files
+- `utils/`: Utility scripts for linting, validation, and build processes
+- `providers/`: React context providers for global state
+
+## Important Patterns
+
+### MDX Page Structure
+All documentation pages use MDX format with frontmatter metadata:
+```mdx
+---
+title: Page Title
+lang: en-US
+description: Page description for SEO
+---
+
+import { ComponentName } from '@/components/ComponentName'
+
+# Content here...
+```
+
+### Component Imports
+Use the configured path alias for component imports:
+```typescript
+import { ComponentName } from '@/components/ComponentName'
+```
+
+### Adding New Documentation
+1. Create MDX file in appropriate `pages/` subdirectory
+2. Include required frontmatter (title, lang, description)
+3. Run `pnpm lint` to validate metadata and content
+4. Use existing components from `components/` directory when possible
+
+### Spell Checking
+- Custom dictionary maintained in `words.txt`
+- Add technical terms using `pnpm spellcheck:fix`
+- Spell checking runs automatically in the lint pipeline
+
+## Git Workflow
+- **Pre-push hook**: Automatically runs `pnpm fix` via Husky
+- **Auto-commit**: Fixes are automatically committed if changes are made
+- **No pre-commit hooks**: Only validation on push
+
+## Special Features
+- **Kapa.ai Widget**: AI assistant integrated for documentation queries
+- **Algolia Search**: Full-text search across documentation
+- **Feelback**: User feedback collection system
+- **Growth Book**: A/B testing framework for feature experiments
+
+## Common Tasks
+
+### Adding a New Page
+1. Create `.mdx` file in appropriate `pages/` directory
+2. Add frontmatter with title, lang, and description
+3. Write content using Markdown and import React components as needed
+4. Run `pnpm dev` to preview
+5. Run `pnpm lint` before committing
+
+### Updating Components
+- Components are in `components/` directory
+- Follow existing patterns and TypeScript types
+- Test component changes across multiple pages that use them
+
+### Working with Images
+- Place images in `public/img/` directory
+- Reference using `/img/filename.ext` in MDX files
+- Optimize images before adding to repository
+
+## Notes
+- The repository uses automated quality checks - always run `pnpm lint` before pushing
+- Netlify handles deployment automatically on merge to main
+- TypeScript is configured with relaxed strict mode - follow existing patterns
+- MDX allows mixing Markdown with React components - leverage this for interactive content
\ No newline at end of file
diff --git a/components/AskAIButton.tsx b/components/AskAIButton.tsx
index 344e20d17..1a6b13c0d 100644
--- a/components/AskAIButton.tsx
+++ b/components/AskAIButton.tsx
@@ -2,7 +2,13 @@ import { RiSparkling2Fill } from '@remixicon/react';
import { useFeature } from '@growthbook/growthbook-react';
import { useEffect, useState } from 'react';
-const AskAIButton = () => {
+interface AskAIButtonProps {
+ fullWidth?: boolean;
+ large?: boolean;
+ id?: string;
+}
+
+const AskAIButton = ({ fullWidth = false, large = false, id = 'custom-ask-ai-button' }: AskAIButtonProps) => {
const [mounted, setMounted] = useState(false);
const enableDocsAIWidget = useFeature('enable_docs_ai_widget').on;
@@ -19,10 +25,17 @@ const AskAIButton = () => {
return null;
}
+ const baseClasses = 'nx-flex nx-gap-2 nx-items-center nx-rounded-lg nx-font-semibold nx-justify-center';
+ const sizeClasses = large
+ ? 'nx-py-3 nx-px-6 nx-text-base'
+ : 'nx-py-1.5 nx-px-3 nx-text-sm';
+ const widthClasses = fullWidth ? 'nx-w-full' : '';
+ const iconSize = large ? 16 : 14;
+
return (
{
}}
>
Ask AI
-
+
);
};
diff --git a/components/CustomHeader/index.tsx b/components/CustomHeader/index.tsx
new file mode 100644
index 000000000..997853ba0
--- /dev/null
+++ b/components/CustomHeader/index.tsx
@@ -0,0 +1,273 @@
+/** @format */
+
+import React, { useState, useEffect } from 'react';
+import Link from 'next/link';
+import { useRouter } from 'next/router';
+import { Search } from '../Search';
+import { AskAIButton } from '../AskAIButton';
+import { useTheme } from 'nextra-theme-docs';
+import { MoonIcon, SunIcon, Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline';
+
+const CustomHeader = () => {
+ const router = useRouter();
+ const { theme, setTheme } = useTheme();
+ const [mounted, setMounted] = useState(false);
+ const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
+ const [isDesktop, setIsDesktop] = useState(false);
+ const [isNavigating, setIsNavigating] = useState(false);
+
+ useEffect(() => {
+ setMounted(true);
+
+ const checkScreenSize = () => {
+ setIsDesktop(window.innerWidth >= 768);
+ };
+
+ checkScreenSize();
+ window.addEventListener('resize', checkScreenSize);
+
+ return () => window.removeEventListener('resize', checkScreenSize);
+ }, []);
+
+ useEffect(() => {
+ const handleStart = () => setIsNavigating(true);
+ const handleComplete = () => setIsNavigating(false);
+
+ router.events.on('routeChangeStart', handleStart);
+ router.events.on('routeChangeComplete', handleComplete);
+ router.events.on('routeChangeError', handleComplete);
+
+ return () => {
+ router.events.off('routeChangeStart', handleStart);
+ router.events.off('routeChangeComplete', handleComplete);
+ router.events.off('routeChangeError', handleComplete);
+ };
+ }, [router]);
+
+ useEffect(() => {
+ const handleEscape = (e: KeyboardEvent) => {
+ if (e.key === 'Escape') {
+ setIsMobileMenuOpen(false);
+ }
+ };
+
+ if (isMobileMenuOpen) {
+ document.addEventListener('keydown', handleEscape);
+ document.body.style.overflow = 'hidden';
+ return () => {
+ document.removeEventListener('keydown', handleEscape);
+ document.body.style.overflow = '';
+ };
+ } else {
+ document.body.style.overflow = '';
+ }
+ }, [isMobileMenuOpen]);
+
+ const navItems = [
+ { title: 'Get started', href: '/get-started/superchain' },
+ { title: 'Superchain', href: '/superchain/superchain-explainer' },
+ { title: 'Interoperability', href: '/interop/get-started' },
+ { title: 'App Devs', href: '/app-developers/get-started' },
+ { title: 'Operators', href: '/operators/chain-operators/architecture' },
+ { title: 'OP Stack', href: '/stack/getting-started' }
+ ];
+
+ const isActive = (href: string) => {
+ return router.pathname.startsWith(href);
+ };
+
+ const handleMouseEnter = (href: string) => {
+ router.prefetch(href);
+ };
+
+ if (!mounted) return null;
+
+ return (
+
+ {/* Top Section: Logo, Search, Actions */}
+
+ {/* Logo */}
+
+
+
+
+
+
+
+ {/* Search Bar - hidden on mobile, shown on larger screens */}
+ {isDesktop && (
+
+
+
+ )}
+
+ {/* Right side: Ask AI + Theme Toggle + Mobile Menu Button */}
+
+
+
+ setTheme(theme === 'dark' ? 'light' : 'dark')}
+ >
+ {theme === 'dark' ? (
+
+ ) : (
+
+ )}
+
+
+
+ {/* Mobile menu button - only visible on mobile */}
+ {!isDesktop && (
+
setIsMobileMenuOpen(!isMobileMenuOpen)}
+ >
+ {isMobileMenuOpen ? (
+
+ ) : (
+
+ )}
+
+ )}
+
+
+
+ {/* Mobile search bar - only visible on mobile */}
+ {!isDesktop && (
+
+
+
+ )}
+
+ {/* Desktop Navigation */}
+ {isDesktop && (
+
+
+
+ {navItems.map((item) => (
+ handleMouseEnter(item.href)}
+ className={`nx-text-sm nx-font-semibold nx-px-4 nx-py-2 nx-transition-all nx-duration-200 ${
+ isActive(item.href)
+ ? 'nx-text-primary-600 dark:nx-text-primary-400'
+ : 'nx-text-gray-600 hover:nx-text-gray-900 dark:nx-text-gray-400 dark:hover:nx-text-gray-100'
+ } ${isNavigating ? 'nx-opacity-70 nx-pointer-events-none' : ''}`}
+ >
+ {item.title}
+
+ ))}
+
+
+
+ )}
+
+ {/* Mobile Full-Screen Menu Overlay */}
+ {!isDesktop && (
+
+ {/* Mobile Menu Header */}
+
+
setIsMobileMenuOpen(false)}
+ className='nx-flex nx-items-center'
+ >
+
+
+
+
+
+
setIsMobileMenuOpen(false)}
+ >
+
+
+
+
+ {/* Mobile Menu Content - Scrollable */}
+
+ {/* Navigation Links */}
+
+
+ {navItems.map((item) => (
+ handleMouseEnter(item.href)}
+ onClick={() => setIsMobileMenuOpen(false)}
+ className={`nx-text-lg nx-font-semibold nx-py-2 nx-transition-all nx-duration-200 nx-block nx-text-gray-700 hover:nx-text-gray-900 dark:nx-text-gray-300 dark:hover:nx-text-gray-100 ${isNavigating ? 'nx-opacity-70 nx-pointer-events-none' : ''}`}
+ >
+ {item.title}
+
+ ))}
+
+
+
+ {/* Mobile Actions - Bottom of menu */}
+
+
+ setTheme(theme === 'dark' ? 'light' : 'dark')}
+ >
+ {theme === 'dark' ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+ )}
+
+ );
+};
+
+export default CustomHeader;
diff --git a/components/HomeCard.tsx b/components/HomeCard.tsx
new file mode 100644
index 000000000..2d040e020
--- /dev/null
+++ b/components/HomeCard.tsx
@@ -0,0 +1,134 @@
+import React from 'react';
+
+interface CardListItemProps {
+ number?: string;
+ title: string;
+ description?: string;
+ href: string;
+ badge?: {
+ text: string;
+ variant: 'easy' | 'medium' | 'hard';
+ };
+}
+
+export function CardListItem({
+ number,
+ title,
+ description,
+ href,
+ badge
+}: CardListItemProps) {
+ return (
+
+ {number && (
+
+ {number}
+
+ )}
+
+
+
{title}
+ {badge && (
+
+ {badge.text}
+
+ )}
+
+ {description && (
+
{description}
+ )}
+
+
+
+ );
+}
+
+interface CardListProps {
+ children: React.ReactNode;
+}
+
+export function CardList({ children }: CardListProps) {
+ return (
+
+ {children}
+
+ );
+}
+
+interface HomeCardProps {
+ title: string;
+ content?: React.ReactNode
+ className?: string;
+ footerLink?: {
+ text: string;
+ href: string;
+ };
+}
+
+export function HomeCard({
+ title,
+ content,
+ className = '',
+ footerLink
+}: HomeCardProps) {
+ return (
+
+
+
+
{title}
+ {content}
+
+
+ {footerLink && (
+
+ )}
+
+ );
+}
+
+interface HomeCardsProps {
+ children: React.ReactNode;
+ layout?: 'equal' | 'unequal';
+ columns?: string;
+ gap?: string;
+}
+
+export function HomeCards({
+ children,
+ layout = 'equal',
+ columns,
+ gap = '2rem'
+}: HomeCardsProps) {
+ const getGridColumns = () => {
+ if (columns) return columns;
+
+ switch (layout) {
+ case 'equal': return '1fr 1fr';
+ case 'unequal': return '1fr 2fr'; // 2:1 ratio
+ default: return '1fr 1fr';
+ }
+ };
+
+ return (
+
+ {children}
+
+ );
+}
\ No newline at end of file
diff --git a/components/LoadingBar/index.tsx b/components/LoadingBar/index.tsx
new file mode 100644
index 000000000..33de15ac7
--- /dev/null
+++ b/components/LoadingBar/index.tsx
@@ -0,0 +1,55 @@
+import React, { useState, useEffect } from 'react';
+import { useRouter } from 'next/router';
+
+const LoadingBar = () => {
+ const [loading, setLoading] = useState(false);
+ const [progress, setProgress] = useState(0);
+ const router = useRouter();
+
+ useEffect(() => {
+ let progressTimer: NodeJS.Timeout;
+ let finishTimer: NodeJS.Timeout;
+
+ const handleStart = () => {
+ setLoading(true);
+ setProgress(0);
+
+ progressTimer = setTimeout(() => {
+ setProgress(70);
+ }, 200);
+ };
+
+ const handleComplete = () => {
+ setProgress(100);
+ finishTimer = setTimeout(() => {
+ setLoading(false);
+ setProgress(0);
+ }, 300);
+ };
+
+ router.events.on('routeChangeStart', handleStart);
+ router.events.on('routeChangeComplete', handleComplete);
+ router.events.on('routeChangeError', handleComplete);
+
+ return () => {
+ router.events.off('routeChangeStart', handleStart);
+ router.events.off('routeChangeComplete', handleComplete);
+ router.events.off('routeChangeError', handleComplete);
+ clearTimeout(progressTimer);
+ clearTimeout(finishTimer);
+ };
+ }, [router]);
+
+ if (!loading) return null;
+
+ return (
+
+ );
+};
+
+export default LoadingBar;
\ No newline at end of file
diff --git a/components/Search/docsearch.tsx b/components/Search/docsearch.tsx
index 902a5c34c..1687b6808 100644
--- a/components/Search/docsearch.tsx
+++ b/components/Search/docsearch.tsx
@@ -1,26 +1,16 @@
-import { Transition } from "@headlessui/react";
-import cn from "clsx";
-import { useRouter } from "next/router";
-import { useMounted } from "nextra/hooks";
-import { InformationCircleIcon, SpinnerIcon } from "nextra/icons";
-import type {
- ReactNode,
- CompositionEvent,
- KeyboardEvent,
- ReactElement,
-} from "react";
-import {
- Fragment,
- useCallback,
- useEffect,
- useRef,
- useState,
- useContext,
-} from "react";
-import { Input } from "./input";
-import Link from "next/link";
-import * as aa from "search-insights";
-import AlgoliaContext from "@/utils/contexts/AlgoliaContext";
+/** @format */
+
+import { Transition } from '@headlessui/react';
+import cn from 'clsx';
+import { useRouter } from 'next/router';
+import { useMounted } from 'nextra/hooks';
+import { InformationCircleIcon, SpinnerIcon } from 'nextra/icons';
+import type { ReactNode, CompositionEvent, KeyboardEvent, ReactElement } from 'react';
+import { Fragment, useCallback, useEffect, useRef, useState, useContext } from 'react';
+import { Input } from './input';
+import Link from 'next/link';
+import * as aa from 'search-insights';
+import AlgoliaContext from '@/utils/contexts/AlgoliaContext';
type SearchResult = {
children: ReactNode;
@@ -40,7 +30,7 @@ type SearchProps = {
results: SearchResult[];
};
-const INPUTS = ["input", "select", "button", "textarea"];
+const INPUTS = ['input', 'select', 'button', 'textarea'];
export function DocSearch({
className,
@@ -50,7 +40,7 @@ export function DocSearch({
onActive,
loading,
error,
- results,
+ results
}: SearchProps): ReactElement {
const [show, setShow] = useState(false);
const [active, setActive] = useState(0);
@@ -78,22 +68,21 @@ export function DocSearch({
)
return;
if (
- e.key === "/" ||
- (e.key === "k" &&
- (e.metaKey /* for Mac */ || /* for non-Mac */ e.ctrlKey))
+ e.key === '/' ||
+ (e.key === 'k' && (e.metaKey /* for Mac */ || /* for non-Mac */ e.ctrlKey))
) {
e.preventDefault();
// prevent scrolling to the top
input.current.focus({ preventScroll: true });
- } else if (e.key === "Escape") {
+ } else if (e.key === 'Escape') {
setShow(false);
input.current.blur();
}
};
- window.addEventListener("keydown", down);
+ window.addEventListener('keydown', down);
return () => {
- window.removeEventListener("keydown", down);
+ window.removeEventListener('keydown', down);
};
}, []);
@@ -102,31 +91,28 @@ export function DocSearch({
const result = results[i];
- aa.default("clickedObjectIDsAfterSearch", {
- index: "docs",
- eventName: "Search Option Clicked",
+ aa.default('clickedObjectIDsAfterSearch', {
+ index: 'docs',
+ eventName: 'Search Option Clicked',
queryID: queryID,
objectIDs: [result.id],
- positions: [results.indexOf(result) + 1],
+ positions: [results.indexOf(result) + 1]
});
setObjectID(result.id);
- onChange("");
+ onChange('');
setShow(false);
};
- const handleActive = useCallback(
- (e: { currentTarget: { dataset: DOMStringMap } }) => {
- const { index } = e.currentTarget.dataset;
- setActive(Number(index));
- },
- []
- );
+ const handleActive = useCallback((e: { currentTarget: { dataset: DOMStringMap } }) => {
+ const { index } = e.currentTarget.dataset;
+ setActive(Number(index));
+ }, []);
const handleKeyDown = useCallback(
function (e: KeyboardEvent) {
switch (e.key) {
- case "ArrowDown": {
+ case 'ArrowDown': {
if (active + 1 < results.length) {
const el = ulRef.current?.querySelector(
`li:nth-of-type(${active + 2}) > a`
@@ -139,7 +125,7 @@ export function DocSearch({
}
break;
}
- case "ArrowUp": {
+ case 'ArrowUp': {
if (active - 1 >= 0) {
const el = ulRef.current?.querySelector(
`li:nth-of-type(${active}) > a`
@@ -152,7 +138,7 @@ export function DocSearch({
}
break;
}
- case "Enter": {
+ case 'Enter': {
const result = results[active];
if (result && composition) {
void router.push(result.route);
@@ -160,7 +146,7 @@ export function DocSearch({
}
break;
}
- case "Escape": {
+ case 'Escape': {
setShow(false);
input.current?.blur();
break;
@@ -177,57 +163,49 @@ export function DocSearch({
{
- onChange("");
+ onChange('');
}}
>
{value && focused
- ? "ESC"
+ ? 'ESC'
: mounted &&
- (navigator.userAgent.includes("Macintosh") ? (
+ (navigator.userAgent.includes('Macintosh') ? (
<>
- ⌘ K
+ ⌘ K
>
) : (
- "CTRL K"
+ 'CTRL K'
))}
);
- const handleComposition = useCallback(
- (e: CompositionEvent) => {
- setComposition(e.type === "compositionend");
- },
- []
- );
+ const handleComposition = useCallback((e: CompositionEvent) => {
+ setComposition(e.type === 'compositionend');
+ }, []);
return (
-
- {renderList && (
-
setShow(false)}
- />
- )}
+
+ {renderList &&
setShow(false)} />}
@@ -256,41 +234,47 @@ export function DocSearch({
show={renderList}
// Transition.Child is required here, otherwise popup will be still present in DOM after focus out
as={Transition.Child}
- leave="nx-transition-opacity nx-duration-100"
- leaveFrom="nx-opacity-100"
- leaveTo="nx-opacity-0"
+ leave='nx-transition-opacity nx-duration-100'
+ leaveFrom='nx-opacity-100'
+ leaveTo='nx-opacity-0'
>
{error ? (
-
-
- {"Error"}
+
+
+ {'Error'}
) : loading ? (
-
-
- {"Loading"}
+
+
+ {'Loading'}
) : results.length > 0 ? (
results.map(({ route, prefix, children, id }, i) => (
@@ -298,15 +282,15 @@ export function DocSearch({
{prefix}
))
) : (
-
+
No results found.
)}
-
+
diff --git a/components/Search/index.tsx b/components/Search/index.tsx
index f1442cf1a..230e1a1cb 100644
--- a/components/Search/index.tsx
+++ b/components/Search/index.tsx
@@ -1,18 +1,20 @@
-import type { Item as NormalItem } from "nextra/normalize-pages";
-import type { ReactElement } from "react";
-import { useContext, useEffect, useState } from "react";
-import { HighlightMatches } from "./highlight-matches";
-import { DocSearch } from "./docsearch";
-import algoliasearch from "algoliasearch";
-import AlgoliaContext from "@/utils/contexts/AlgoliaContext";
+/** @format */
+
+import type { Item as NormalItem } from 'nextra/normalize-pages';
+import type { ReactElement } from 'react';
+import { useContext, useEffect, useState } from 'react';
+import { HighlightMatches } from './highlight-matches';
+import { DocSearch } from './docsearch';
+import algoliasearch from 'algoliasearch';
+import AlgoliaContext from '@/utils/contexts/AlgoliaContext';
// Using environment variables for Algolia configuration
const client = algoliasearch(
- process.env.NEXT_PUBLIC_ALGOLIA_APPLICATION_ID || "",
- process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_API_KEY || ""
+ process.env.NEXT_PUBLIC_ALGOLIA_APPLICATION_ID || '',
+ process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_API_KEY || ''
);
-const index = client.initIndex(process.env.NEXT_PUBLIC_ALGOLIA_INDEX_NAME || "docs");
+const index = client.initIndex(process.env.NEXT_PUBLIC_ALGOLIA_INDEX_NAME || 'docs');
type AlgoliaHits = {
hits: AlgoliaHit[];
@@ -28,13 +30,13 @@ export type AlgoliaHit = {
export function Search({
className,
- directories,
+ directories
}: Readonly<{
className?: string;
directories: NormalItem[];
}>): ReactElement {
// Rest of your code remains the same
- const [search, setSearch] = useState("");
+ const [search, setSearch] = useState('');
const [results, setResults] = useState([]);
const { queryID, setQueryID } = useContext(AlgoliaContext);
@@ -42,7 +44,7 @@ export function Search({
useEffect(() => {
async function fetchData() {
const hits: AlgoliaHits = await index.search(search, {
- clickAnalytics: true,
+ clickAnalytics: true
});
setQueryID(hits.queryID);
@@ -53,11 +55,11 @@ export function Search({
children: (
<>
-
+
>
- ),
+ )
}));
setResults(mappedHits);
}
@@ -70,8 +72,8 @@ export function Search({
value={search}
onChange={setSearch}
className={className}
- overlayClassName="nx-w-screen nx-min-h-[100px] nx-max-w-[min(calc(100vw-2rem),calc(100%+20rem))]"
+ overlayClassName='nx-min-h-[100px] nx-w-[600px] nx-max-w-[calc(100vw-2rem)] nx-left-1/2 -nx-translate-x-1/2'
results={results}
/>
);
-}
\ No newline at end of file
+}
diff --git a/package.json b/package.json
index 97163bd87..9ad08ac64 100644
--- a/package.json
+++ b/package.json
@@ -28,6 +28,7 @@
"@feelback/react": "^0.3.4",
"@growthbook/growthbook-react": "^1.3.1",
"@headlessui/react": "^2.1.8",
+ "@heroicons/react": "^2.2.0",
"@remixicon/react": "^4.6.0",
"algoliasearch": "^4.23.3",
"clsx": "^2.1.1",
diff --git a/pages/_app.tsx b/pages/_app.tsx
index b32bfeab1..8ee602e60 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -6,6 +6,7 @@ import * as gtag from '../utils/gtag';
import * as aa from 'search-insights';
import AlgoliaContext from '@/utils/contexts/AlgoliaContext';
import ScrollDispatcher from '@/components/ScrollDispatcher';
+import LoadingBar from '@/components/LoadingBar';
import { CustomGrowthBookProvider } from '../providers/GrowthbookProvider';
export default function App({ Component, pageProps }) {
@@ -31,6 +32,7 @@ export default function App({ Component, pageProps }) {
return (
+
- } />
- } />
- } />
-
-
-## Builder guides
-
-Whether you're a developer building an app on OP Mainnet, a node operator running an OP Mainnet node, or a chain operator launching your own OP Stack chain, you'll find everything you need to get started right here.
-
-
- } />
-
- } />
-
- } />
-
- } />
-
-
-## Featured tools
-
-Check out these amazing tools, so you can get building with Optimism.
-
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
-
-
-## About Optimism
-
-The OP Stack is the standardized, shared, and open-source development stack that makes it easy to spin up your own production-ready Layer 2 blockchain.
-The Superchain is a network of OP Stack chains that share a bridging protocol, governance system, and more.
-We've got you covered with these detailed guides to help you learn all about Optimism's tech stack.
-
-
- } />
-
- } />
-
- } />
-
+import { HomeCards, HomeCard, CardList, CardListItem } from '@/components/HomeCard'
+
+
+
+
Deploy a chain with the OP Stack
+
Launch your own OP Chain using standard configuration, or customize your setup.
+
+
+ View Deployment Guide
+ Explore Tutorials
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ footerLink={{
+ text: "View full deployment guide",
+ href: "https://github.com/ethereum-optimism/docs/issues"
+ }}
+ />
+
+
+
+
+
+
+
+ }
+ footerLink={{
+ text: "View all tutorials",
+ href: "https://github.com/ethereum-optimism/docs/issues"
+ }}
+ />
+
+
+
+
+
+
+
+
+
+
+ }
+ />
+
+
+
+
+
+
+
+
+ }
+ />
+
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1af8e1d27..b4184220d 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -34,6 +34,9 @@ importers:
'@headlessui/react':
specifier: ^2.1.8
version: 2.1.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
+ '@heroicons/react':
+ specifier: ^2.2.0
+ version: 2.2.0(react@18.2.0)
'@remixicon/react':
specifier: ^4.6.0
version: 4.6.0(react@18.2.0)
@@ -63,10 +66,10 @@ importers:
version: 4.2.3(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))
nextra:
specifier: 2.13.2
- version: 2.13.2(patch_hash=a4rp2hgojklggjmthmkiyqaek4)(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
+ version: 2.13.2(patch_hash=81936321c37741ec218dc19817c4a4939f4655b8371e793561fc236bebccc249)(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
nextra-theme-docs:
specifier: 2.13.2
- version: 2.13.2(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(nextra@2.13.2(patch_hash=a4rp2hgojklggjmthmkiyqaek4)(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
+ version: 2.13.2(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(nextra@2.13.2(patch_hash=81936321c37741ec218dc19817c4a4939f4655b8371e793561fc236bebccc249)(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react:
specifier: ^18.2.0
version: 18.2.0
@@ -130,7 +133,7 @@ importers:
version: 15.0.1
remark-code-import:
specifier: ^1.2.0
- version: 1.2.0(patch_hash=heylvfasxh3ubj2edns2svea2m)
+ version: 1.2.0(patch_hash=f6b78667b2fd0da0247b6e898a35f71bfde2a83adfa62fa6017a02dc7fb5d436)
remark-frontmatter:
specifier: ^5.0.0
version: 5.0.0
@@ -139,7 +142,7 @@ importers:
version: 3.0.1
remark-lint-frontmatter-schema:
specifier: ^3.15.4
- version: 3.15.4(patch_hash=jaxvkozlhcbn7zjsiti5ocoubi)
+ version: 3.15.4(patch_hash=32c1574b8fd989888047ea0226d42029f451eb7c875349c28b6259a73cc7e59f)
remark-lint-heading-style:
specifier: ^3.1.2
version: 3.1.2
@@ -653,6 +656,11 @@ packages:
react: ^18
react-dom: ^18
+ '@heroicons/react@2.2.0':
+ resolution: {integrity: sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==}
+ peerDependencies:
+ react: '>= 16 || ^19.0.0-rc'
+
'@humanwhocodes/config-array@0.11.13':
resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==}
engines: {node: '>=10.10.0'}
@@ -4718,6 +4726,10 @@ snapshots:
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
+ '@heroicons/react@2.2.0(react@18.2.0)':
+ dependencies:
+ react: 18.2.0
+
'@humanwhocodes/config-array@0.11.13':
dependencies:
'@humanwhocodes/object-schema': 2.0.1
@@ -7617,7 +7629,7 @@ snapshots:
- '@babel/core'
- babel-plugin-macros
- nextra-theme-docs@2.13.2(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(nextra@2.13.2(patch_hash=a4rp2hgojklggjmthmkiyqaek4)(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
+ nextra-theme-docs@2.13.2(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(nextra@2.13.2(patch_hash=81936321c37741ec218dc19817c4a4939f4655b8371e793561fc236bebccc249)(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@headlessui/react': 1.7.17(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@popperjs/core': 2.11.8
@@ -7631,13 +7643,13 @@ snapshots:
next: 14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
next-seo: 6.4.0(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
next-themes: 0.2.1(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
- nextra: 2.13.2(patch_hash=a4rp2hgojklggjmthmkiyqaek4)(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
+ nextra: 2.13.2(patch_hash=81936321c37741ec218dc19817c4a4939f4655b8371e793561fc236bebccc249)(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
scroll-into-view-if-needed: 3.1.0
zod: 3.22.4
- nextra@2.13.2(patch_hash=a4rp2hgojklggjmthmkiyqaek4)(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
+ nextra@2.13.2(patch_hash=81936321c37741ec218dc19817c4a4939f4655b8371e793561fc236bebccc249)(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@headlessui/react': 1.7.17(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@mdx-js/mdx': 2.3.0
@@ -7959,7 +7971,7 @@ snapshots:
hast-util-raw: 9.0.1
vfile: 6.0.1
- remark-code-import@1.2.0(patch_hash=heylvfasxh3ubj2edns2svea2m):
+ remark-code-import@1.2.0(patch_hash=f6b78667b2fd0da0247b6e898a35f71bfde2a83adfa62fa6017a02dc7fb5d436):
dependencies:
strip-indent: 4.0.0
to-gatsby-remark-plugin: 0.1.0
@@ -8032,7 +8044,7 @@ snapshots:
unified: 10.1.2
unified-lint-rule: 2.1.2
- remark-lint-frontmatter-schema@3.15.4(patch_hash=jaxvkozlhcbn7zjsiti5ocoubi):
+ remark-lint-frontmatter-schema@3.15.4(patch_hash=32c1574b8fd989888047ea0226d42029f451eb7c875349c28b6259a73cc7e59f):
dependencies:
'@apidevtools/json-schema-ref-parser': 11.1.0
ajv: 8.12.0
diff --git a/public/img/cube.png b/public/img/cube.png
new file mode 100644
index 000000000..48375e5cc
Binary files /dev/null and b/public/img/cube.png differ
diff --git a/styles/global.css b/styles/global.css
index 06a25fa39..68c566995 100644
--- a/styles/global.css
+++ b/styles/global.css
@@ -289,4 +289,317 @@ div.footer-columns {
background-color: transparent !important;
--tw-shadow-color: transparent !important;
box-shadow: none !important;
- }
\ No newline at end of file
+ }
+
+/* Hero section styles */
+.hero-section {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ min-height: 500px;
+ padding: 4rem 0;
+ margin-bottom: 4rem;
+}
+
+.hero-content {
+ flex: 1;
+ max-width: 505px;
+}
+
+.hero-content h1 {
+ font-size: 2rem;
+ font-weight: 400;
+ line-height: 1.1;
+ margin-bottom: 1.5rem;
+}
+
+.hero-content p {
+ font-size: 1.125rem;
+ line-height: 1.6;
+ margin-bottom: 2rem;
+ color: var(--op-neutral-500);
+}
+
+:is(html[class~=dark]) .hero-content p {
+ color: var(--op-neutral-500);
+}
+
+.hero-buttons {
+ display: flex;
+ gap: 1rem;
+}
+
+.btn-primary {
+ background-color: var(--op-red-500);
+ color: white;
+ padding: 0.75rem 1rem;
+ border: none;
+ border-radius: 6px;
+ font-weight: 400;
+ cursor: pointer;
+ transition: background-color 0.2s;
+}
+
+.btn-primary:hover {
+ background-color: var(--op-red-600);
+}
+
+.btn-secondary {
+ background-color: transparent;
+ color: var(--op-neutral-800);
+ padding: 0.75rem 1.5rem;
+ border: 1px solid var(--op-neutral-400);
+ border-radius: 6px;
+ font-weight: 400;
+ cursor: pointer;
+ transition: all 0.2s;
+}
+
+.btn-secondary:hover {
+ background-color: var(--op-neutral-100);
+ border-color: var(--op-neutral-500);
+}
+
+:is(html[class~=dark]) .btn-secondary {
+ color: white;
+ border-color: var(--op-neutral-600);
+}
+
+:is(html[class~=dark]) .btn-secondary:hover {
+ background-color: var(--op-neutral-800);
+ border-color: var(--op-neutral-500);
+}
+
+@media (max-width: 768px) {
+ .hero-section {
+ flex-direction: column;
+ text-align: center;
+ min-height: auto;
+ padding: 2rem 0;
+ }
+
+ .hero-content {
+ padding-right: 0;
+ margin-bottom: 2rem;
+ }
+
+ .hero-content h1 {
+ font-size: 2rem;
+ }
+
+ .hero-buttons {
+ justify-content: center;
+ }
+}
+
+/* Home Cards Component Styles */
+.home-cards {
+ width: 100%;
+ margin-bottom: 2rem;
+}
+
+.home-card {
+ display: flex;
+ flex-direction: column;
+ padding: 1.5rem;
+ background: var(--op-neutral-50);
+ border: 1px solid var(--op-neutral-200);
+ border-radius: 8px;
+ transition: all 0.2s ease;
+}
+
+:is(html[class~=dark]) .home-card {
+ background: var(--op-neutral-800);
+ border-color: var(--op-neutral-700);
+}
+
+/* Card Content */
+.home-card .home-card__title {
+ font-size: 1.25rem !important;
+ font-weight: 400 !important;
+ margin: 0 0 2rem 0;
+ color: var(--op-neutral-900);
+}
+
+:is(html[class~=dark]) .home-card .home-card__title {
+ color: var(--op-neutral-100) !important;
+}
+
+.home-card__footer {
+ margin-top: 2rem;
+ padding-top: 1rem;
+}
+
+:is(html[class~=dark]) .home-card__footer {
+ border-top-color: var(--op-neutral-700);
+}
+
+.home-card__footer-link {
+ color: var(--op-neutral-600);
+ text-decoration: none;
+ font-size: 0.875rem;
+ font-weight: 500;
+ transition: font-weight 0.2s ease;
+}
+
+.home-card__footer-link:hover {
+ font-weight: 600;
+}
+
+:is(html[class~=dark]) .home-card__footer-link {
+ color: var(--op-neutral-400);
+}
+
+/* Card List Components */
+.card-list {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+}
+
+.card-list-item {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ padding-bottom: 1.25rem;
+ border-radius: 6px;
+ text-decoration: none;
+ color: inherit;
+ transition: all 0.2s ease;
+}
+
+.card-list-item:hover .card-list-item__title {
+ font-weight: 600;
+}
+
+.card-list-item:hover .card-list-item__description {
+ color: var(--op-neutral-800);
+}
+
+:is(html[class~=dark]) .card-list-item:hover .card-list-item__description {
+ color: var(--op-neutral-200);
+}
+
+.card-list-item__number {
+ width: 2rem;
+ height: 2rem;
+ border-radius: 50%;
+ background: var(--op-neutral-100);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-weight: 600;
+ font-size: 0.875rem;
+ flex-shrink: 0;
+}
+
+:is(html[class~=dark]) .card-list-item__number {
+ background: var(--op-neutral-700);
+ color: white;
+}
+
+.card-list-item__content {
+ flex: 1;
+}
+
+.card-list-item__header {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ margin-bottom: 0.25rem;
+}
+
+.card-list-item__title {
+ margin: 0;
+ font-size: 1rem;
+ font-weight: 400;
+ color: var(--op-text-900);
+}
+
+:is(html[class~=dark]) .card-list-item__title {
+ color: #BCBFCD;
+}
+
+.card-list-item__description {
+ margin: 0;
+ font-size: 0.875rem;
+ color: var(--op-neutral-600);
+ line-height: 1.4;
+}
+
+:is(html[class~=dark]) .card-list-item__description {
+ color: var(--op-neutral-400);
+}
+
+.card-list-item__badge {
+ padding: 0.125rem 0.5rem;
+ border-radius: 12px;
+ font-size: 0.75rem;
+ font-weight: 600;
+ text-transform: capitalize;
+}
+
+.card-list-item__badge--easy {
+ background: #dcfce7;
+ color: #166534;
+}
+
+.card-list-item__badge--medium {
+ background: #fef3c7;
+ color: #92400e;
+}
+
+.card-list-item__badge--hard {
+ background: #fee2e2;
+ color: #991b1b;
+}
+
+:is(html[class~=dark]) .card-list-item__badge--easy {
+ background: var(--op-yellow-green-900);
+ color: var(--op-green-600);
+}
+
+:is(html[class~=dark]) .card-list-item__badge--medium {
+ background: var(--op-orange-900);
+ color: var(--op-orange-500);
+}
+
+:is(html[class~=dark]) .card-list-item__badge--hard {
+ background: #991b1b;
+ color: #fee2e2;
+}
+
+.card-list-item__arrow {
+ color: var(--op-neutral-400);
+ font-size: 1.25rem;
+ transition: transform 0.2s ease;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.card-list-item:hover .card-list-item__arrow {
+ transform: translateX(2px);
+ color: var(--op-neutral-600);
+}
+
+:is(html[class~=dark]) .card-list-item__arrow {
+ color: var(--op-neutral-500);
+}
+
+:is(html[class~=dark]) .card-list-item:hover .card-list-item__arrow {
+ color: var(--op-neutral-300);
+}
+
+/* Responsive */
+@media (max-width: 768px) {
+ .home-cards {
+ grid-template-columns: 1fr !important;
+ }
+
+ .card-list-item__header {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 0.5rem;
+ }
+}
\ No newline at end of file
diff --git a/theme.config.tsx b/theme.config.tsx
index 143030bac..a3798144e 100644
--- a/theme.config.tsx
+++ b/theme.config.tsx
@@ -9,29 +9,13 @@ import '@feelback/react/styles/feelback.css';
import { Search } from './components/Search';
import { Footer } from './components/Footer';
import { AskAIButton } from './components/AskAIButton';
+import CustomHeader from './components/CustomHeader';
import { useFeature } from '@growthbook/growthbook-react';
const config: DocsThemeConfig = {
- logo: (
- <>
-
-
-
-
- >
- ),
+ navbar: {
+ component: CustomHeader
+ },
darkMode: true,
// banner: {
// key: 'viem/op-stack',
@@ -42,12 +26,6 @@ const config: DocsThemeConfig = {
//
// )
// },
- search: {
- component: Search
- },
- navbar: {
- extraContent: AskAIButton
- },
docsRepositoryBase: 'https://github.com/ethereum-optimism/docs/blob/main/',
footer: {
text:
diff --git a/words.txt b/words.txt
index 05708699c..9fd4ba285 100644
--- a/words.txt
+++ b/words.txt
@@ -1,7 +1,7 @@
-ACCOUNTQUEUE
accountqueue
-ACCOUNTSLOTS
+ACCOUNTQUEUE
accountslots
+ACCOUNTSLOTS
ACDC
ADDI
ADDIU
@@ -9,58 +9,58 @@ ADDU
airgap
Allnodes
allocs
-Alphanet
alphanet
-Alphanets
+Alphanet
alphanets
+Alphanets
altda
ANDI
Ankr
Apeworx
Arweave
authrpc
-Autorelay
autorelay
+Autorelay
autorelayer
basefee
bcde
-Betanet
betanet
-Betanets
+Betanet
betanets
+Betanets
BGEZ
BGTZ
Biconomy
BLEZ
-BLOBPOOL
blobpool
+BLOBPOOL
blobspace
Blockdaemon
blockhash
blocklists
-BLOCKLOGS
blocklogs
-BLOCKPROFILERATE
+BLOCKLOGS
blockprofilerate
+BLOCKPROFILERATE
Blockscout
-Blockspace
blockspace
+Blockspace
blocktime
-Blocktimes
blocktimes
-BLOOMFILTER
+Blocktimes
bloomfilter
+BLOOMFILTER
BLTZ
Bootcamp
bootnode
-BOOTNODES
-Bootnodes
bootnodes
+Bootnodes
+BOOTNODES
bottlenecked
-Brotli
brotli
-Callouts
+Brotli
callouts
+Callouts
CCIP
cdef
Celestia
@@ -73,66 +73,66 @@ chaosnet
Chugsplash
Clabby
codebases
-Collateralized
collateralized
+Collateralized
compr
Comprensive
-COMPUTEPENDINGBLOCK
computependingblock
+COMPUTEPENDINGBLOCK
confs
corsdomain
counterfactually
-Crosschain
crosschain
+Crosschain
Crossmint
daserver
-DATACAP
datacap
-DATADIR
+DATACAP
datadir
+DATADIR
Defi
Defillama's
delegatecall
-Devnet
devnet
-Devnets
+Devnet
devnets
+Devnets
devs
direnv
-DISABLETXPOOLGOSSIP
disabletxpoolgossip
-Discv
+DISABLETXPOOLGOSSIP
discv
+Discv
DIVU
Drand
dripcheck
Drippie
Eigen
EIPs
-ENABLEDEPRECATEDPERSONAL
enabledeprecatedpersonal
+ENABLEDEPRECATEDPERSONAL
enginekind
-Erigon
erigon
-ETHERBASE
+Erigon
etherbase
+ETHERBASE
Ethernity
Ethernow
-ETHSTATS
ethstats
-EVMTIMEOUT
+ETHSTATS
evmtimeout
+EVMTIMEOUT
executability
exfiltrate
-EXITWHENSYNCED
exitwhensynced
+EXITWHENSYNCED
extensibly
-EXTRADATA
extradata
+EXTRADATA
Farcaster
Faultproof
-FDLIMIT
fdlimit
+FDLIMIT
Flashblocks
Flashbots
forkable
@@ -141,51 +141,51 @@ FPVM
FPVMs
Fraxtal
Funct
-GASCAP
gascap
+GASCAP
gaslessly
-GCMODE
gcmode
+GCMODE
Gelato
gifs
-GLOBALQUEUE
globalqueue
-GLOBALSLOTS
+GLOBALQUEUE
globalslots
+GLOBALSLOTS
gokzg
growthepie
hardfork
hardforks
-HEALTHCHECK
healthcheck
+HEALTHCHECK
healthchecks
-HISTORICALRPC
historicalrpc
-HISTORICALRPCTIMEOUT
+HISTORICALRPC
historicalrpctimeout
-HOLESKY
-Holesky
+HISTORICALRPCTIMEOUT
holesky
+Holesky
+HOLESKY
IERC
-IGNOREPRICE
ignoreprice
+IGNOREPRICE
Immunefi
-Inator
inator
-INFLUXDBV
+Inator
influxdbv
+INFLUXDBV
initcode
-IPCDISABLE
ipcdisable
+IPCDISABLE
ipcfile
-IPCPATH
ipcpath
+IPCPATH
IPFS
JALR
-JOURNALREMOTES
journalremotes
-JSPATH
+JOURNALREMOTES
jspath
+JSPATH
jwtsecret
Keccak
leveldb
@@ -194,34 +194,34 @@ Lisk
logfile
logfmt
Mainnets
-MAXAGE
maxage
-MAXBACKUPS
+MAXAGE
maxbackups
-MAXPEERS
+MAXBACKUPS
maxpeers
-MAXPENDPEERS
+MAXPEERS
maxpendpeers
-MAXPRICE
+MAXPENDPEERS
maxprice
-MEMPROFILERATE
+MAXPRICE
memprofilerate
-Merkle
+MEMPROFILERATE
merkle
+Merkle
MFHI
MFLO
Mgas
Minato
-MINFREEDISK
minfreedisk
-MINSUGGESTEDPRIORITYFEE
+MINFREEDISK
minsuggestedpriorityfee
+MINSUGGESTEDPRIORITYFEE
Mintable
Mintplex
MIPSEVM
Mitigations
-Monitorism
monitorism
+Monitorism
Moralis
Mordor
mountpoint
@@ -231,145 +231,145 @@ MTHI
MTLO
MULT
multiaddr
-Multichain
multichain
+Multichain
multiclient
multisigs
MULTU
Nethermind
-NETRESTRICT
netrestrict
-NETWORKID
+NETRESTRICT
networkid
-NEWPAYLOAD
+NETWORKID
newpayload
+NEWPAYLOAD
nextra
-NOCOMPACTION
nocompaction
-NODEKEY
+NOCOMPACTION
nodekey
-NODEKEYHEX
+NODEKEY
nodekeyhex
+NODEKEYHEX
nodename
Nodies
-NODISCOVER
nodiscover
-NOLOCALS
+NODISCOVER
nolocals
-NOPREFETCH
+NOLOCALS
noprefetch
-NOPRUNING
+NOPREFETCH
nopruning
-NOSYNCSERVE
+NOPRUNING
nosyncserve
+NOSYNCSERVE
Numba
NVME
-Offchain
offchain
+Offchain
onlyreqtostatic
opchaina
opchainb
-OPCM
opcm
+OPCM
Openfort
oplabs
opnode's
outfile
outperformance
pcscdpath
-Pectra
pectra
+Pectra
Pectra's
-Peerstore
peerstore
+Peerstore
peerstores
-Permissioned
permissioned
+Permissioned
permissioning
-Permissionless
permissionless
+Permissionless
permissionlessly
Perps
Peta
Pimlico
POAP
POAPs
-PPROF
pprof
-Precommitments
+PPROF
precommitments
+Precommitments
preconfigured
predeploy
-Predeployed
predeployed
-Predeploys
+Predeployed
predeploys
+Predeploys
prefunded
-Preimage
preimage
-PREIMAGES
+Preimage
preimages
+PREIMAGES
preinstall
-Preinstalls
preinstalls
-Prestate
+Preinstalls
prestate
+Prestate
prestates
PREVRANDAO
-PRICEBUMP
pricebump
-PRICELIMIT
+PRICEBUMP
pricelimit
+PRICELIMIT
productionize
productionized
Protip
Proxied
-Proxyd
proxyd
+Proxyd
Pyth
Pyth's
QRNG
-Quicknode
quicknode
+Quicknode
quickstarts
rebalancing
reemit
Reemitting
-Regenesis
regenesis
+Regenesis
Reimagine
-REJOURNAL
rejournal
-REMOTEDB
+REJOURNAL
remotedb
+REMOTEDB
Reown
Reown's
replayability
replayor
reposts
reproven
-REQUIREDBLOCKS
requiredblocks
+REQUIREDBLOCKS
rollouts
-Rollups
rollups
+Rollups
Routescan
rpckind
-RPCPREFIX
rpcprefix
+RPCPREFIX
rpcs
RPGF
-Runbooks
runbooks
+Runbooks
RWAs
safedb
Schnorr
-SEPOLIA
-Sepolia
sepolia
+Sepolia
+SEPOLIA
seqnr
-SEQUENCERHTTP
sequencerhttp
+SEQUENCERHTTP
serv
signup
SLLV
@@ -378,16 +378,16 @@ SLTIU
SLTU
smartcard
snapshotlog
-Snapsync
snapsync
+Snapsync
Solana
Soneium
soyboy
Spearbit
SRAV
SRLV
-Stablecoins
stablecoins
+Stablecoins
statefulset
structs
subcomponents
@@ -396,21 +396,21 @@ subheaders
subsecond
SUBU
Sunnyside
-SUPERCHAIN
-Superchain
superchain
+Superchain
+SUPERCHAIN
Superchain's
superchainerc
Superlend
Superloans
Superscan
Superseed
-Supersim
supersim
-SYNCMODE
+Supersim
syncmode
-SYNCTARGET
+SYNCMODE
synctarget
+SYNCTARGET
syscalls
SYSCON
thirdweb
@@ -424,8 +424,8 @@ Twei
txfeecap
txmgr
txns
-TXPOOL
txpool
+TXPOOL
txproxy
txproxyd
uncensorable
@@ -436,21 +436,21 @@ Unprotect
unsubmitted
UPNP
upstreaming
-VERKLE
verkle
-VHOSTS
+VERKLE
vhosts
-Viem
+VHOSTS
viem
-Viem's
+Viem
viem's
-VMDEBUG
+Viem's
vmdebug
-VMODULE
+VMDEBUG
vmodule
+VMODULE
xlarge
XORI
ZKPs
ZKVM
-Zora
zora
+Zora