diff --git a/public/img/platform-logos/AWS.svg b/public/img/platform-logos/AWS.svg new file mode 100644 index 00000000..9fd688c4 --- /dev/null +++ b/public/img/platform-logos/AWS.svg @@ -0,0 +1 @@ +Amazon AWS \ No newline at end of file diff --git a/public/img/platform-logos/Android.svg b/public/img/platform-logos/Android.svg new file mode 100644 index 00000000..3f44ef6b --- /dev/null +++ b/public/img/platform-logos/Android.svg @@ -0,0 +1 @@ +Android \ No newline at end of file diff --git a/public/img/platform-logos/Apple.svg b/public/img/platform-logos/Apple.svg new file mode 100644 index 00000000..de4b0d17 --- /dev/null +++ b/public/img/platform-logos/Apple.svg @@ -0,0 +1 @@ +Apple \ No newline at end of file diff --git a/public/img/platform-logos/Azure.svg b/public/img/platform-logos/Azure.svg new file mode 100644 index 00000000..69a264e2 --- /dev/null +++ b/public/img/platform-logos/Azure.svg @@ -0,0 +1 @@ +Microsoft Azure \ No newline at end of file diff --git a/public/img/platform-logos/Cloudflare.svg b/public/img/platform-logos/Cloudflare.svg new file mode 100644 index 00000000..a1cf2d6d --- /dev/null +++ b/public/img/platform-logos/Cloudflare.svg @@ -0,0 +1 @@ +Cloudflare \ No newline at end of file diff --git a/public/img/platform-logos/Espressif.svg b/public/img/platform-logos/Espressif.svg new file mode 100644 index 00000000..36c82bcc --- /dev/null +++ b/public/img/platform-logos/Espressif.svg @@ -0,0 +1 @@ +Espressif \ No newline at end of file diff --git a/public/img/platform-logos/JavaScript.svg b/public/img/platform-logos/JavaScript.svg new file mode 100644 index 00000000..91e51623 --- /dev/null +++ b/public/img/platform-logos/JavaScript.svg @@ -0,0 +1 @@ +JavaScript \ No newline at end of file diff --git a/public/img/platform-logos/Kotlin.svg b/public/img/platform-logos/Kotlin.svg new file mode 100644 index 00000000..adf2975b --- /dev/null +++ b/public/img/platform-logos/Kotlin.svg @@ -0,0 +1 @@ +Kotlin \ No newline at end of file diff --git a/public/img/platform-logos/Linux.svg b/public/img/platform-logos/Linux.svg new file mode 100644 index 00000000..381d3d8a --- /dev/null +++ b/public/img/platform-logos/Linux.svg @@ -0,0 +1 @@ +Linux \ No newline at end of file diff --git a/public/img/platform-logos/RaspberryPi.svg b/public/img/platform-logos/RaspberryPi.svg new file mode 100644 index 00000000..1325a023 --- /dev/null +++ b/public/img/platform-logos/RaspberryPi.svg @@ -0,0 +1 @@ +Raspberry Pi \ No newline at end of file diff --git a/public/img/platform-logos/Rust.svg b/public/img/platform-logos/Rust.svg new file mode 100644 index 00000000..b95ce42a --- /dev/null +++ b/public/img/platform-logos/Rust.svg @@ -0,0 +1 @@ +Rust \ No newline at end of file diff --git a/public/img/platform-logos/Swift.svg b/public/img/platform-logos/Swift.svg new file mode 100644 index 00000000..ffaf098e --- /dev/null +++ b/public/img/platform-logos/Swift.svg @@ -0,0 +1 @@ +Swift \ No newline at end of file diff --git a/public/img/platform-logos/Windows.svg b/public/img/platform-logos/Windows.svg new file mode 100644 index 00000000..aca1d539 --- /dev/null +++ b/public/img/platform-logos/Windows.svg @@ -0,0 +1 @@ +Windows \ No newline at end of file diff --git a/public/img/user-logos/meshllm.svg b/public/img/user-logos/meshllm.svg new file mode 100644 index 00000000..f5bf350c --- /dev/null +++ b/public/img/user-logos/meshllm.svg @@ -0,0 +1,15 @@ + + mesh-llm + + + + + + + + + + + mesh-llm + + diff --git a/public/img/user-logos/ottomatic.png b/public/img/user-logos/ottomatic.png new file mode 100644 index 00000000..80958cd7 Binary files /dev/null and b/public/img/user-logos/ottomatic.png differ diff --git a/public/img/user-logos/strada.png b/public/img/user-logos/strada.png new file mode 100644 index 00000000..3fd36001 Binary files /dev/null and b/public/img/user-logos/strada.png differ diff --git a/src/app/blog/layout.jsx b/src/app/blog/layout.jsx index 7360264a..0a090e16 100644 --- a/src/app/blog/layout.jsx +++ b/src/app/blog/layout.jsx @@ -10,7 +10,9 @@ export default function DocsLayout({children, sections = {}}) { return ( - {children} +
+ {children} +
); } \ No newline at end of file diff --git a/src/app/blog/page.jsx b/src/app/blog/page.jsx index d7ccc646..d90496f7 100644 --- a/src/app/blog/page.jsx +++ b/src/app/blog/page.jsx @@ -50,7 +50,7 @@ export default async function ArticlesIndex() {

Blog

-

all things iroh & development

+

all things iroh & development

diff --git a/src/app/layout.jsx b/src/app/layout.jsx index 19dadc88..07e7bbcf 100644 --- a/src/app/layout.jsx +++ b/src/app/layout.jsx @@ -44,7 +44,7 @@ export default async function RootLayout({children}) { - +
diff --git a/src/app/legal/page.jsx b/src/app/legal/page.jsx index 0cb97277..6659c668 100644 --- a/src/app/legal/page.jsx +++ b/src/app/legal/page.jsx @@ -11,7 +11,7 @@ export default function LegalPage() {
-
+
{/* Hero */}
diff --git a/src/app/page.jsx b/src/app/page.jsx index b4133184..25128721 100644 --- a/src/app/page.jsx +++ b/src/app/page.jsx @@ -1,7 +1,7 @@ import Image from 'next/image' import Link from 'next/link' import { ArrowRightIcon } from '@heroicons/react/24/outline' -import { Cpu } from 'lucide-react' +import { SquareCheck } from 'lucide-react' import {FooterMarketing} from '@/components/FooterMarketing'; import {HeaderSparse} from '@/components/HeaderSparse'; @@ -13,10 +13,14 @@ import { IrohEverywhere } from '@/components/IrohEverywhere'; import {ProtocolHeroList} from '@/components/ProtocolHeroList'; import {LogoCloud} from '@/components/home/LogoCloud'; -import {HomeFeatureTabs} from '@/components/HomeFeatureTabs'; +import { OpenSourceIllustration } from '@/components/OpenSourceIllustration'; import logoRust from '@/images/language-logos/rust.svg'; -import { CodeBlock } from '@/components/CodeBlock'; +import logoSwift from '@/images/language-logos/swift.svg'; +import logoJavascript from '@/images/language-logos/node.svg'; +import logoKotlin from '@/images/language-logos/kotlin.svg'; +import logoPython from '@/images/language-logos/python.svg'; +import { CodeBlockTabs } from '@/components/CodeBlockTabs'; export const metadata = { title: 'Iroh', @@ -24,58 +28,89 @@ export const metadata = { 'less net work for networks', }; +const languages = [ + { name: 'Swift', logo: logoSwift, href: 'https://docs.iroh.computer/languages/swift' }, + { name: 'Rust', logo: logoRust, href: 'https://docs.iroh.computer/languages/rust' }, + { name: 'JavaScript', logo: logoJavascript, href: 'https://docs.iroh.computer/languages/javascript' }, + { name: 'Kotlin', logo: logoKotlin, href: 'https://docs.iroh.computer/languages/kotlin' }, + { name: 'Python', logo: logoPython, href: 'https://docs.iroh.computer/languages/python' }, +]; + +const platforms = [ + { name: 'Raspberry Pi', file: 'RaspberryPi', color: '#A22846' }, + { name: 'Espressif', file: 'Espressif', color: '#E7352C' }, + { name: 'Linux', file: 'Linux', color: '#B8860B' }, + { name: 'Windows', file: 'Windows', color: '#0078D4' }, + { name: 'Apple', file: 'Apple' }, + { name: 'Android', file: 'Android', color: '#34A853' }, +]; + +function PlatformLogo({ name, file, href, color, logo }) { + const Wrapper = href ? 'a' : 'div'; + return ( + + {logo ? ( + + ) : ( + + ); +} + export default function Page() { return (
-
+
{/* hero */} -
+
-
-
+
+

IP addresses break, dial keys instead

- -

Add peer-to-peer connectivity to your app, anywhere: servers, mobile apps, agents, desktops, and embedded systems.

+

+ Add peer-to-peer connectivity to your app, agent, or workflow. +

+ {/* real-world use */}
-
-
-

- Fast connections. -
- Anywhere. -
- Forever. -

-

- No VPNs, user accounts, or proprietary networks. - The core peer-to-peer technology is open source and built on open standards, so you're never locked in: connect over our free community relays, self-host your own, or let us run them for you, and switch between them whenever you want. -

-
-
- -
+
-
+
@@ -95,67 +130,87 @@ export default function Page() {
- + {/* supported platforms */} +
+ +
+ {languages.map((logo) => ( + + ))} +
+
+ {platforms.map((logo) => ( + + ))} +
+
+ + {/* reach every device */} +
+
+
+

Built for environments where connectivity is unreliable or intermittent

+
    +
  • +
  • +
  • +
  • +
  • +
  • +
+
+
+ +
+
+
{/* Solutions */}

How are people using iroh?

-
- -
-
-

Distributed AI Training

-

Train foundation LLMs with compute distributed around the world, across AWS, GCP, Azure, and self-hosted infrastructure.

-
-
- Nous logo -
+
+ +
+

Distributed AI Training

+

Train foundation LLMs with compute distributed around the world, across AWS, GCP, Azure, and self-hosted infrastructure.

- -
-
-

Video Streaming

-

Stream video between devices, using peer to peer technology. Create encrypted connections built on open standards, across the globe or across the room.

-
-
- Rave logo -
+ +
+

Video Streaming

+

Stream video between devices, using peer to peer technology. Create encrypted connections built on open standards, across the globe or across the room.

- -
-
-

Real-time Sync for Mobile Applications

-

Powers apps for hundreds of thousands of devices around the world, even when internet access is precarious.

-
-
- Delta Chat logo -
+ +
+

Real-time Sync for Mobile Applications

+

Powers apps for hundreds of thousands of devices around the world, even when internet access is precarious.

- -
-
-

Point of Sale Payments

-

Connect payment terminals directly to point of sale systems over Bluetooth, LAN, or Wi-Fi with full PCI compliance and no additional servers.

-
-
- Paycode logo -
+ +
+

Point of Sale Payments

+

Connect payment terminals directly to point of sale systems over Bluetooth, LAN, or Wi-Fi with full PCI compliance and no additional servers.

- -
-
-

IoT & Embedded Devices

-

Run iroh on ESP32, Raspberry Pi, and Linux with the same API. Devices discover each other automatically — no brokers, no gateways.

-
-
- -
+ +
+

IoT & Embedded Devices

+

Run iroh on ESP32, Raspberry Pi, and Linux with the same API. Devices discover each other automatically. No brokers, no gateways.

+
+ + +
+

File Transfer & Sync

+

Move files and large blobs directly between devices with content-addressed, resumable transfers that verify every byte.

@@ -164,18 +219,29 @@ export default function Page() {
-

Deploy, Monitor, Fix

-

All commits to iroh's main branch run through a growing set of simulations & tests.

-

- iroh provides opt-in - observability and - network diagnostics. Track connection health and throughput across all your devices and services. -

-

- You'll see how much of your traffic goes direct versus through a relay: a fallback server iroh uses when two devices can't reach each other directly, always end-to-end encrypted. Compare plans. -

- - Monitor your App +

Ready for production

+ + + Get help from the pros
@@ -184,12 +250,18 @@ export default function Page() {
- {/* iroh protocols */} -
-

Modular toolkit

-

- Dozens of open-source, composable protocols built on top of iroh. Mix & match to get the feature set you need.

- + +
+
+

+ Open source. +
+ Forever. +

+

+ The core peer-to-peer technology is open source and built on open standards, so you're never locked in: connect over our free community relays, self-host your own, let us run them for you, and switch between them whenever you want. +

+
{/* build in your language */} @@ -197,14 +269,21 @@ export default function Page() {
-
+ {[ + { logo: logoSwift, name: 'Swift' }, + { logo: logoRust, name: 'Rust' }, + { logo: logoJavascript, name: 'JavaScript' }, + { logo: logoKotlin, name: 'Kotlin' }, + { logo: logoPython, name: 'Python' }, + ].map(({ logo, name }) => ( -
+ /> + ))}

Start building.

@@ -212,10 +291,18 @@ export default function Page() {
- +
+ + {/* iroh protocols */} +
+

Modular toolkit

+

+ Dozens of open-source, composable protocols built on top of iroh. Mix & match to get the feature set you need.

+ +

From the Blog

@@ -230,26 +317,122 @@ export default function Page() { } -const codeSample = `// a program that creates two endpoints & sends a ping between them -use anyhow::Result; -use iroh::{Endpoint, protocol::Router}; -use iroh_ping::Ping; +// Minimal "dial a peer and echo a message" flow in each language. +// APIs match the iroh-ffi endpoint tests and the Rust quickstart docs. +const codeSnippets = [ + { + title: 'Swift', + label: 'App.swift', + language: 'swift', + code: `import IrohLib + +@main +struct App { + static func main() async throws { + // Dial a peer and echo a message over a bidirectional stream. + let endpoint = try await Endpoint.bind( + options: EndpointOptions(preset: presetN0()) + ) + + let conn = try await endpoint.connect(addr: serverAddr, alpn: ALPN) + let bi = try await conn.openBi() + + try await bi.send().writeAll(buf: Data("hello iroh".utf8)) + try await bi.send().finish() + + let echoed = try await bi.recv().readToEnd(sizeLimit: 64) + print(String(decoding: echoed, as: UTF8.self)) + } +}`, + }, + { + title: 'Rust', + label: 'main.rs', + language: 'rust', + code: `use anyhow::Result; +use iroh::{Endpoint, endpoint::presets}; #[tokio::main] async fn main() -> Result<()> { - // create the receive side - let recv_ep = Endpoint::builder().bind().await?; - let recv_router = Router::builder(recv_ep.clone()) - .accept(iroh_ping::ALPN, Ping::new()) - .spawn(); - recv_ep.online().await; - let addr = recv_router.endpoint().addr(); - - // create a send side & send a ping - let send_ep = Endpoint::builder().bind().await?; - let send_pinger = Ping::new(); - let rtt = send_pinger.ping(&send_ep, addr).await?; - println!("ping took: {rtt:?} to complete"); + // Dial a peer and echo a message over a bidirectional stream. + let endpoint = Endpoint::bind(presets::N0).await?; + + let conn = endpoint.connect(server_addr, ALPN).await?; + let (mut send, mut recv) = conn.open_bi().await?; + + send.write_all(b"hello iroh").await?; + send.finish()?; + let echoed = recv.read_to_end(64).await?; + println!("{}", String::from_utf8_lossy(&echoed)); Ok(()) -}` +}`, + }, + { + title: 'JavaScript', + label: 'index.js', + language: 'javascript', + code: `const { Endpoint } = require('@number0/iroh') + +async function main() { + // Dial a peer and echo a message over a bidirectional stream. + const builder = Endpoint.builder() + builder.applyN0() + const endpoint = await builder.bind() + + const conn = await endpoint.connect(serverAddr, ALPN) + const bi = await conn.openBi() + + await bi.send.writeAll(Array.from(Buffer.from('hello iroh'))) + await bi.send.finish() + + const echoed = await bi.recv.readToEnd(64) + console.log(Buffer.from(echoed).toString()) +} + +main()`, + }, + { + title: 'Kotlin', + label: 'Main.kt', + language: 'kotlin', + code: `import computer.iroh.* +import kotlinx.coroutines.runBlocking + +fun main() = runBlocking { + // Dial a peer and echo a message over a bidirectional stream. + val endpoint = Endpoint.bind(EndpointOptions(preset = presetN0())) + + val conn = endpoint.connect(serverAddr, ALPN) + val bi = conn.openBi() + + bi.send().writeAll("hello iroh".toByteArray()) + bi.send().finish() + + val echoed = bi.recv().readToEnd(64u) + println(String(echoed)) +}`, + }, + { + title: 'Python', + label: 'main.py', + language: 'python', + code: `import asyncio +from iroh import Endpoint, EndpointOptions, preset_n0 + +async def main(): + # Dial a peer and echo a message over a bidirectional stream. + endpoint = await Endpoint.bind(EndpointOptions(preset=preset_n0())) + + conn = await endpoint.connect(server_addr, ALPN) + bi = await conn.open_bi() + + await bi.send().write_all(b"hello iroh") + await bi.send().finish() + + echoed = await bi.recv().read_to_end(64) + print(echoed.decode()) + +asyncio.run(main())`, + }, +] diff --git a/src/app/pricing/page.jsx b/src/app/pricing/page.jsx index ae7fa616..737fb98d 100644 --- a/src/app/pricing/page.jsx +++ b/src/app/pricing/page.jsx @@ -128,7 +128,7 @@ export default function PricingPage() {
-
+
{/* Hero */}
diff --git a/src/app/providers.jsx b/src/app/providers.jsx index d659167d..79bb19f5 100644 --- a/src/app/providers.jsx +++ b/src/app/providers.jsx @@ -7,7 +7,7 @@ export const AppContext = createContext({}) export function Providers({ children }) { return ( - + {children} ); diff --git a/src/app/services/enterprise/page.tsx b/src/app/services/enterprise/page.tsx index b5d68710..701d41c9 100644 --- a/src/app/services/enterprise/page.tsx +++ b/src/app/services/enterprise/page.tsx @@ -28,7 +28,7 @@ export default function EnterprisePage() {
-
+
{/* Hero */}
diff --git a/src/app/services/hosting/page.jsx b/src/app/services/hosting/page.jsx index 208395c3..80c0f9d1 100644 --- a/src/app/services/hosting/page.jsx +++ b/src/app/services/hosting/page.jsx @@ -17,7 +17,7 @@ export default function HostingPage() {
-
+
{/* Hero Section */}
diff --git a/src/app/services/observability/page.jsx b/src/app/services/observability/page.jsx index 29eface4..4d61a644 100644 --- a/src/app/services/observability/page.jsx +++ b/src/app/services/observability/page.jsx @@ -15,7 +15,7 @@ export default function MetricsPage() {
-
+
{/* Hero Section */}
diff --git a/src/app/solutions/delta-chat/page.jsx b/src/app/solutions/delta-chat/page.jsx index ae6003a4..9295f7d7 100644 --- a/src/app/solutions/delta-chat/page.jsx +++ b/src/app/solutions/delta-chat/page.jsx @@ -14,7 +14,7 @@ export default function DeltaChatSolutionPage() {
-
+
{/* Hero Section */}
{/* Background Logo */} diff --git a/src/app/solutions/iot/page.jsx b/src/app/solutions/iot/page.jsx index cbcc181d..0fbcffbf 100644 --- a/src/app/solutions/iot/page.jsx +++ b/src/app/solutions/iot/page.jsx @@ -58,7 +58,7 @@ export default function IoTUseCasePage() {
-
+
{/* Hero */}
diff --git a/src/app/solutions/nous/page.jsx b/src/app/solutions/nous/page.jsx index 4d42adef..58d41f79 100644 --- a/src/app/solutions/nous/page.jsx +++ b/src/app/solutions/nous/page.jsx @@ -15,7 +15,7 @@ export default function NousUseCasePage() {
-
+
{/* Hero Section */}
{/* Background Logo */} diff --git a/src/app/solutions/page.jsx b/src/app/solutions/page.jsx index 70b03c8d..49592118 100644 --- a/src/app/solutions/page.jsx +++ b/src/app/solutions/page.jsx @@ -57,7 +57,7 @@ export default function SolutionsPage() {
-
+
{/* Hero Section */}
diff --git a/src/app/solutions/pos/page.jsx b/src/app/solutions/pos/page.jsx index 77a5f6ba..5510dd58 100644 --- a/src/app/solutions/pos/page.jsx +++ b/src/app/solutions/pos/page.jsx @@ -18,7 +18,7 @@ export default function PaycodeUseCasePage() {
-
+
{/* Hero Section */}
diff --git a/src/app/solutions/video/page.jsx b/src/app/solutions/video/page.jsx index d89186ac..e567f42e 100644 --- a/src/app/solutions/video/page.jsx +++ b/src/app/solutions/video/page.jsx @@ -14,7 +14,7 @@ export default function VideoSolutionsPage() {
-
+
{/* Hero Section */}
{/* Background Logo */} @@ -132,7 +132,7 @@ export default function VideoSolutionsPage() {

- “Media over QUIC has real legs. It works on mobile and handles packet loss so much better.” + “Media over QUIC has real legs. It works on mobile and handles packet loss so much better than WebRTC.”

diff --git a/src/components/BlogPostLayout.jsx b/src/components/BlogPostLayout.jsx index 121e4fa1..d9865c36 100644 --- a/src/components/BlogPostLayout.jsx +++ b/src/components/BlogPostLayout.jsx @@ -28,7 +28,7 @@ export function BlogPostLayout({ article, references = [], children }) {

{article.title}

- + @@ -40,7 +40,7 @@ export function BlogPostLayout({ article, references = [], children }) { {references.length > 0 && ( )} -
+
Iroh is a dial-any-device networking library that just works. Compose from an ecosystem of ready-made protocols to get the features you need, or go fully custom on a clean abstraction over dumb pipes. Iroh is open source, and already running in production on hundreds of thousands of devices.
To get started, take a look at our docs, dive directly into the code, or chat with us in our discord channel.
diff --git a/src/components/CodeBlockTabs.jsx b/src/components/CodeBlockTabs.jsx new file mode 100644 index 00000000..53a6e3ef --- /dev/null +++ b/src/components/CodeBlockTabs.jsx @@ -0,0 +1,43 @@ +import React from 'react'; +import { getHighlighter, renderToHtml } from 'shiki'; +import { CodeGroup } from '@/components/Code'; + +let highlighter; + +// Several syntax-highlighted snippets rendered as a single tabbed CodeGroup. +// `snippets` is an array of { title, label, language, code }. The sibling +// `CodeBlock` component is the single-snippet version of this. +export async function CodeBlockTabs({ snippets }) { + highlighter = + highlighter ?? + (await getHighlighter({ + theme: 'css-variables', + langs: ['rust', 'swift', 'javascript', 'kotlin', 'python'], + })); + + const rendered = snippets.map((snippet) => { + const tokens = highlighter.codeToThemedTokens(snippet.code, snippet.language); + const html = renderToHtml(tokens, { + elements: { + pre: ({ children }) => children, + code: ({ children }) => children, + line: ({ children }) => `${children}`, + }, + }); + return { ...snippet, html }; + }); + + return ( + + {rendered.map((snippet) => ( + + ))} + + ); +} diff --git a/src/components/Header.jsx b/src/components/Header.jsx index b86f300e..05a77fc9 100644 --- a/src/components/Header.jsx +++ b/src/components/Header.jsx @@ -98,7 +98,7 @@ export const Header = forwardRef(function Header({className, sidebar = []}, ref) className={clsx( className, 'fixed inset-x-0 top-[var(--v1-banner-height,0px)] z-50 flex h-14 items-center justify-between gap-12 px-4 transition sm:px-6 lg:left-72 lg:z-30 lg:px-8 xl:left-80', - 'bg-white dark:bg-zinc-900', + 'bg-white dark:bg-black', !isInsideMobileNavigation && 'backdrop-blur-sm dark:backdrop-blur lg:left-72 xl:left-80', )} diff --git a/src/components/HeaderSparse.jsx b/src/components/HeaderSparse.jsx index 6447e53f..5b2e35d0 100644 --- a/src/components/HeaderSparse.jsx +++ b/src/components/HeaderSparse.jsx @@ -6,6 +6,7 @@ import Link from 'next/link'; import {navItems} from '@/components/Header'; import GithubStars from './GithubStars'; import { Button } from './Button'; +import {ThemeToggle} from './ThemeToggle'; function TopLevelNavItem({ href, children }) { return ( @@ -100,7 +101,7 @@ export function HeaderSparse() { return (
@@ -142,7 +146,7 @@ export function HeaderSparse() {
{/* Mobile menu, show/hide based on menu state. */} -