diff --git a/site/.gitignore b/site/.gitignore index c626920..adaa241 100644 --- a/site/.gitignore +++ b/site/.gitignore @@ -2,3 +2,4 @@ node_modules dist .vercel cache +src/pages.gen.ts diff --git a/site/components/FamilyNav.tsx b/site/components/FamilyNav.tsx new file mode 100644 index 0000000..e09b2b2 --- /dev/null +++ b/site/components/FamilyNav.tsx @@ -0,0 +1,47 @@ +/** + * Cross-repo navigation for the tevm.sh family of documentation sites. + * Every entry below is a live site. + */ + +export const FAMILY = [ + { name: 'tevm.sh', url: 'https://tevm.sh', desc: 'The Ethereum toolkit — start here' }, + { name: 'contract.tevm.sh', url: 'https://contract.tevm.sh', desc: 'Typesafe contract bindings' }, + { name: 'bundler.tevm.sh', url: 'https://bundler.tevm.sh', desc: 'Import Solidity from JS' }, + { name: 'cli.tevm.sh', url: 'https://cli.tevm.sh', desc: 'Command line interface' }, + { name: 'test.tevm.sh', url: 'https://test.tevm.sh', desc: 'Contract testing utilities' }, + { name: 'logger.tevm.sh', url: 'https://logger.tevm.sh', desc: 'Structured logging' }, + { name: 'ethers.tevm.sh', url: 'https://ethers.tevm.sh', desc: 'ethers.js integration' }, + { name: 'mud.tevm.sh', url: 'https://mud.tevm.sh', desc: 'MUD framework integration' }, + { name: 'examples.tevm.sh', url: 'https://examples.tevm.sh', desc: 'End-to-end examples' }, + { name: 'voltaire.tevm.sh', url: 'https://voltaire.tevm.sh', desc: 'Ethereum primitives in Zig' }, + { + name: 'guillotine.tevm.sh', + url: 'https://guillotine.tevm.sh', + desc: 'High-performance EVM interpreter', + }, + { name: 'mini.tevm.sh', url: 'https://mini.tevm.sh', desc: 'Minimal spec-faithful EVM' }, + { name: 'zevm.tevm.sh', url: 'https://zevm.tevm.sh', desc: 'Zig Ethereum client (this site)' }, +] + +const CURRENT = 'zevm.tevm.sh' + +export function FamilyNav() { + return ( + + ) +} diff --git a/site/components/Hero.tsx b/site/components/Hero.tsx new file mode 100644 index 0000000..1b2c732 --- /dev/null +++ b/site/components/Hero.tsx @@ -0,0 +1,45 @@ +'use client' + +import { useState } from 'react' + +const INSTALL = 'npm install @evmts/zevm@beta' + +export function Hero() { + const [copied, setCopied] = useState(false) + + const copy = () => { + navigator.clipboard?.writeText(INSTALL) + setCopied(true) + setTimeout(() => setCopied(false), 1500) + } + + return ( +
+

Ethereum client · written in Zig

+

ZEVM

+

+ A writable trusted dev node and a proof-backed light client in one binary — shipped as a + CLI, a C ABI, and a Node.js addon with prebuilt binaries for macOS, Linux and Windows. +

+ +
+ {INSTALL} + +
+ +
+ + Get started + + + CLI reference + + + GitHub + +
+
+ ) +} diff --git a/site/components/PlatformPicker.tsx b/site/components/PlatformPicker.tsx new file mode 100644 index 0000000..e9f1608 --- /dev/null +++ b/site/components/PlatformPicker.tsx @@ -0,0 +1,189 @@ +'use client' + +import { useEffect, useState } from 'react' + +/** + * Interactive platform-support picker. + * + * ZEVM ships one prebuilt native package per platform under `npm/platforms`, + * wired into `@evmts/zevm` as optionalDependencies. This mirrors that table so a + * reader can answer "is my machine supported, and which package do I get?" + * without cross-referencing package.json files. + * + * Source of truth: the package.json of each npm/platforms directory. + */ + +type Target = { + os: string + arch: string + libc?: string + pkg: string +} + +const TARGETS: Target[] = [ + { os: 'darwin', arch: 'arm64', pkg: '@evmts/zevm-darwin-arm64' }, + { os: 'darwin', arch: 'x64', pkg: '@evmts/zevm-darwin-x64' }, + { os: 'linux', arch: 'arm64', libc: 'glibc', pkg: '@evmts/zevm-linux-arm64-gnu' }, + { os: 'linux', arch: 'arm64', libc: 'musl', pkg: '@evmts/zevm-linux-arm64-musl' }, + { os: 'linux', arch: 'x64', libc: 'glibc', pkg: '@evmts/zevm-linux-x64-gnu' }, + { os: 'linux', arch: 'x64', libc: 'musl', pkg: '@evmts/zevm-linux-x64-musl' }, + { os: 'win32', arch: 'arm64', pkg: '@evmts/zevm-win32-arm64-msvc' }, + { os: 'win32', arch: 'ia32', pkg: '@evmts/zevm-win32-ia32-msvc' }, + { os: 'win32', arch: 'x64', pkg: '@evmts/zevm-win32-x64-msvc' }, +] + +const OS_LABELS: Record = { + darwin: 'macOS', + linux: 'Linux', + win32: 'Windows', +} + +const ARCHES = ['arm64', 'x64', 'ia32'] +const LIBCS = ['glibc', 'musl'] + +function find(os: string, arch: string, libc: string) { + return TARGETS.find( + (t) => t.os === os && t.arch === arch && (os === 'linux' ? t.libc === libc : true), + ) +} + +/** Best-effort guess of the visitor's platform from the UA string. */ +function guess(): { os: string; arch: string } { + if (typeof navigator === 'undefined') return { os: 'darwin', arch: 'arm64' } + const ua = navigator.userAgent + const os = /Win/.test(ua) ? 'win32' : /Linux|Android/.test(ua) ? 'linux' : 'darwin' + const arch = /arm|aarch64|Mac OS X/.test(ua) && !/Intel Mac/.test(ua) ? 'arm64' : 'x64' + return { os, arch } +} + +export function PlatformPicker() { + const [os, setOs] = useState('darwin') + const [arch, setArch] = useState('arm64') + const [libc, setLibc] = useState('glibc') + const [copied, setCopied] = useState(false) + + useEffect(() => { + const g = guess() + setOs(g.os) + setArch(g.arch) + }, []) + + // Windows has no arm64/x64/ia32 gap, but arm64 is absent on Windows ia32 etc. + // Keep the selected arch valid whenever the OS changes. + useEffect(() => { + if (!TARGETS.some((t) => t.os === os && t.arch === arch)) { + const first = TARGETS.find((t) => t.os === os) + if (first) setArch(first.arch) + } + }, [os, arch]) + + const match = find(os, arch, libc) + const install = 'npm install @evmts/zevm@beta' + + const copy = () => { + navigator.clipboard?.writeText(install) + setCopied(true) + setTimeout(() => setCopied(false), 1500) + } + + return ( +
+
+
+ + Operating system + +
+ {Object.keys(OS_LABELS).map((value) => ( + + ))} +
+
+ +
+ + Architecture + +
+ {ARCHES.map((value) => { + const available = TARGETS.some((t) => t.os === os && t.arch === value) + return ( + + ) + })} +
+
+ + {os === 'linux' && ( +
+ + libc + +
+ {LIBCS.map((value) => ( + + ))} +
+
+ )} +
+ +
+ {match ? ( + <> +
+ Prebuilt binary + {match.pkg} +
+
+ {install} + +
+

+ npm resolves {match.pkg} automatically through the{' '} + optionalDependencies of @evmts/zevm. Nothing is compiled at + install time. +

+ + ) : ( + <> +
+ No prebuilt binary +
+

+ This combination has no published package. Build the binary yourself — see{' '} + Building From Source. +

+ + )} +
+
+ ) +} diff --git a/site/public/favicon.svg b/site/public/favicon.svg new file mode 100644 index 0000000..654fd43 --- /dev/null +++ b/site/public/favicon.svg @@ -0,0 +1,4 @@ + + + Z + diff --git a/site/public/tevm-logo-dark.png b/site/public/tevm-logo-dark.png new file mode 100644 index 0000000..7fea34a Binary files /dev/null and b/site/public/tevm-logo-dark.png differ diff --git a/site/public/tevm-logo-light.png b/site/public/tevm-logo-light.png new file mode 100644 index 0000000..fc75408 Binary files /dev/null and b/site/public/tevm-logo-light.png differ diff --git a/site/src/pages/_root.css b/site/src/pages/_root.css new file mode 100644 index 0000000..6820b4d --- /dev/null +++ b/site/src/pages/_root.css @@ -0,0 +1,343 @@ +/* + * Shared tevm.sh family theme tokens. + * + * Matched against the live sibling sites (contract.tevm.sh, bundler.tevm.sh), + * which render with --vocs-color-accent:#0085FF and the Geist / Geist Mono + * type stack. Keep this file in sync with the family rather than diverging. + */ + +:root { + --tevm-accent: #0085ff; + --tevm-accent-hover: #339dff; + --tevm-zig: #f7a41d; + + /* + * Vocs derives --vocs-font-sans / --vocs-font-mono from these, and sets + * `color-scheme` on [data-vocs-theme], so light-dark() below resolves + * correctly for BOTH the system preference and the explicit theme toggle. + */ + --vocs-font-family: 'Geist', ui-sans-serif, system-ui, sans-serif; + --vocs-font-family-mono: 'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace; + + --tevm-font-sans: var(--vocs-font-sans, var(--vocs-font-family)); + --tevm-font-mono: var(--vocs-font-mono, var(--vocs-font-family-mono)); + + --tevm-surface: light-dark(#ffffff, #17181c); + --tevm-surface-2: light-dark(#f7f8fa, #1e2027); + --tevm-border: light-dark(#e2e6ec, #2c2f38); + --tevm-text: light-dark(#1b1b1f, #f2f3f5); + --tevm-text-dim: light-dark(#5c6370, #9aa1ad); + --tevm-hero-glow: light-dark(rgba(0, 133, 255, 0.1), rgba(0, 133, 255, 0.16)); + --tevm-ok: light-dark(#0f9d58, #3ecf8e); + --tevm-danger: light-dark(#d93025, #ff6b6b); +} + +/* ---------------------------------------------------------------- hero --- */ + +.tevm-hero { + border: 1px solid var(--tevm-border); + border-radius: 14px; + background: + radial-gradient(120% 130% at 0% 0%, var(--tevm-hero-glow), transparent 62%), + var(--tevm-surface-2); + padding: 32px 28px; + margin: 0 0 40px; +} + +.tevm-hero__eyebrow { + display: inline-flex; + align-items: center; + gap: 8px; + font-family: var(--tevm-font-mono); + font-size: 12px; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--tevm-text-dim); + margin: 0 0 14px; +} + +.tevm-hero__eyebrow::before { + content: ''; + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--tevm-zig); +} + +.tevm-hero__title { + font-size: clamp(30px, 5vw, 44px); + line-height: 1.1; + font-weight: 600; + letter-spacing: -0.02em; + margin: 0 0 12px; + color: var(--tevm-text); +} + +.tevm-hero__tagline { + font-size: 17px; + line-height: 1.55; + color: var(--tevm-text-dim); + max-width: 62ch; + margin: 0 0 22px; +} + +.tevm-hero__install { + display: flex; + align-items: stretch; + gap: 0; + border: 1px solid var(--tevm-border); + border-radius: 8px; + background: var(--tevm-surface); + overflow: hidden; + max-width: 420px; +} + +.tevm-hero__install code { + flex: 1; + font-family: var(--tevm-font-mono); + font-size: 14px; + padding: 11px 14px; + color: var(--tevm-text); + white-space: nowrap; + overflow-x: auto; + background: none; + border: none; +} + +.tevm-copy { + border: none; + border-left: 1px solid var(--tevm-border); + background: var(--tevm-surface-2); + color: var(--tevm-text-dim); + font-family: var(--tevm-font-mono); + font-size: 12px; + padding: 0 14px; + cursor: pointer; + transition: color 0.15s, background 0.15s; +} + +.tevm-copy:hover { + color: var(--tevm-accent); + background: var(--tevm-surface); +} + +.tevm-hero__ctas { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-top: 20px; +} + +.tevm-hero__cta { + display: inline-block; + padding: 9px 16px; + border-radius: 8px; + font-size: 14px; + font-weight: 500; + text-decoration: none; + border: 1px solid var(--tevm-border); + color: var(--tevm-text); +} + +.tevm-hero__cta--primary { + background: var(--tevm-accent); + border-color: var(--tevm-accent); + color: #fff; +} + +.tevm-hero__cta--primary:hover { + background: var(--tevm-accent-hover); + border-color: var(--tevm-accent-hover); +} + +.tevm-hero__cta:hover { + border-color: var(--tevm-accent); +} + +/* ------------------------------------------------------- platform picker --- */ + +.zevm-platform { + border: 1px solid var(--tevm-border); + border-radius: 12px; + background: var(--tevm-surface-2); + padding: 20px; + margin: 28px 0; +} + +.zevm-platform__row { + display: flex; + flex-wrap: wrap; + gap: 20px; + margin-bottom: 18px; +} + +.zevm-platform__group { + display: flex; + flex-direction: column; + gap: 7px; +} + +.zevm-platform__label { + font-family: var(--tevm-font-mono); + font-size: 11px; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--tevm-text-dim); +} + +.zevm-platform__options { + display: flex; + gap: 6px; + flex-wrap: wrap; +} + +.zevm-chip { + font-family: var(--tevm-font-mono); + font-size: 13px; + padding: 6px 12px; + border-radius: 999px; + border: 1px solid var(--tevm-border); + background: var(--tevm-surface); + color: var(--tevm-text-dim); + cursor: pointer; + transition: all 0.15s; +} + +.zevm-chip:hover:not(:disabled) { + border-color: var(--tevm-accent); + color: var(--tevm-text); +} + +.zevm-chip[aria-pressed='true'] { + background: var(--tevm-accent); + border-color: var(--tevm-accent); + color: #fff; +} + +.zevm-chip:disabled { + opacity: 0.35; + cursor: not-allowed; + text-decoration: line-through; +} + +.zevm-platform__result { + border-top: 1px solid var(--tevm-border); + padding-top: 16px; +} + +.zevm-platform__pkg { + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; + margin-bottom: 10px; +} + +.zevm-platform__pkg code { + font-family: var(--tevm-font-mono); + font-size: 14px; + color: var(--tevm-text); + background: var(--tevm-surface); + border: 1px solid var(--tevm-border); + border-radius: 6px; + padding: 4px 10px; +} + +.zevm-badge { + font-family: var(--tevm-font-mono); + font-size: 11px; + padding: 3px 8px; + border-radius: 999px; + border: 1px solid var(--tevm-border); + color: var(--tevm-text-dim); +} + +.zevm-badge--ok { + color: var(--tevm-ok); + border-color: currentColor; +} + +.zevm-badge--none { + color: var(--tevm-danger); + border-color: currentColor; +} + +.zevm-platform__note { + font-size: 13px; + line-height: 1.55; + color: var(--tevm-text-dim); + margin: 10px 0 0; +} + +.zevm-platform__note a { + color: var(--tevm-accent); +} + +/* Keep inline code in the note tight so the sentence reads as one line. */ +.zevm-platform__note code { + font-family: var(--tevm-font-mono); + font-size: 0.92em; + padding: 0 2px; + margin: 0; + background: none; + border: none; + color: var(--tevm-text); + word-spacing: normal; +} + +/* ------------------------------------------------------------ family nav --- */ + +.tevm-family { + border-top: 1px solid var(--tevm-border); + margin-top: 48px; + padding-top: 22px; +} + +.tevm-family__title { + font-family: var(--tevm-font-mono); + font-size: 11px; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--tevm-text-dim); + margin: 0 0 14px; +} + +.tevm-family__grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); + gap: 8px; +} + +.tevm-family__item { + display: block; + border: 1px solid var(--tevm-border); + border-radius: 8px; + background: var(--tevm-surface-2); + padding: 10px 12px; + text-decoration: none; + transition: border-color 0.15s, background 0.15s; +} + +.tevm-family__item:hover { + border-color: var(--tevm-accent); + background: var(--tevm-surface); +} + +.tevm-family__item[aria-current='page'] { + border-color: var(--tevm-accent); +} + +.tevm-family__name { + display: block; + font-family: var(--tevm-font-mono); + font-size: 13px; + color: var(--tevm-accent); +} + +.tevm-family__desc { + display: block; + font-size: 12px; + line-height: 1.4; + color: var(--tevm-text-dim); + margin-top: 2px; +} diff --git a/site/src/pages/index.mdx b/site/src/pages/index.mdx index 82833cc..cf60139 100644 --- a/site/src/pages/index.mdx +++ b/site/src/pages/index.mdx @@ -3,7 +3,11 @@ title: ZEVM description: A Zig Ethereum client with a writable trusted dev node and a proof-backed light client. --- -# ZEVM +import { Hero } from '../../components/Hero' +import { PlatformPicker } from '../../components/PlatformPicker' +import { FamilyNav } from '../../components/FamilyNav' + + ZEVM is an Ethereum client written in Zig. It runs in exactly two modes: @@ -47,6 +51,8 @@ npm install @evmts/zevm@beta Or build the binary from source — see [Installation](/quickstart/installation) and [Building From Source](/guides/building-from-source). + + ## Start a dev node ```bash @@ -85,3 +91,5 @@ ZEVM is pre-1.0. The first real release is `0.1.0-beta.1`; the public API and na usable, but cross-platform packaging still wants consumer feedback. Phase-1 scope means HTTP JSON-RPC only — no built-in TLS and no JSON-RPC authentication. Keep `--host 127.0.0.1` unless you have put a reverse proxy in front of it. + + diff --git a/site/src/pages/quickstart/installation.mdx b/site/src/pages/quickstart/installation.mdx index 7e6f40e..be17da3 100644 --- a/site/src/pages/quickstart/installation.mdx +++ b/site/src/pages/quickstart/installation.mdx @@ -5,8 +5,12 @@ description: Build ZEVM from source and run it locally. # Installation +import { PlatformPicker } from '../../../components/PlatformPicker' + ZEVM can be built from source or from release artifact jobs. Source builds use Zig package-manager pins in `build.zig.zon`. + + ## Prerequisites - Zig `0.15.2` or newer (`minimum_zig_version` in `build.zig.zon`) diff --git a/site/vocs.config.ts b/site/vocs.config.ts index 12dba8a..a3297b8 100644 --- a/site/vocs.config.ts +++ b/site/vocs.config.ts @@ -6,6 +6,12 @@ export default defineConfig({ 'ZEVM is a Zig Ethereum client with a writable trusted dev node and a proof-backed light client, distributed as a binary, a C ABI, and a Node.js addon.', baseUrl: 'https://zevm.tevm.sh', rootDir: '.', + // Shared tevm.sh family identity — matches contract.tevm.sh / bundler.tevm.sh. + logoUrl: { light: '/tevm-logo-light.png', dark: '/tevm-logo-dark.png' }, + iconUrl: '/favicon.svg', + // Same accent the sibling family sites render with. + accentColor: '#0085FF', + colorScheme: 'light dark', editLink: { pattern: 'https://github.com/evmts/zevm/edit/main/site/src/pages/:path', text: 'Edit on GitHub', @@ -21,6 +27,24 @@ export default defineConfig({ text: 'npm', link: 'https://www.npmjs.com/package/@evmts/zevm', }, + { + text: 'tevm family', + items: [ + { text: 'tevm.sh', link: 'https://tevm.sh' }, + { text: 'contract', link: 'https://contract.tevm.sh' }, + { text: 'bundler', link: 'https://bundler.tevm.sh' }, + { text: 'cli', link: 'https://cli.tevm.sh' }, + { text: 'test', link: 'https://test.tevm.sh' }, + { text: 'logger', link: 'https://logger.tevm.sh' }, + { text: 'ethers', link: 'https://ethers.tevm.sh' }, + { text: 'mud', link: 'https://mud.tevm.sh' }, + { text: 'examples', link: 'https://examples.tevm.sh' }, + { text: 'voltaire', link: 'https://voltaire.tevm.sh' }, + { text: 'guillotine', link: 'https://guillotine.tevm.sh' }, + { text: 'mini', link: 'https://mini.tevm.sh' }, + { text: 'zevm', link: 'https://zevm.tevm.sh' }, + ], + }, ], sidebar: [ { text: 'Introduction', link: '/' },