diff --git a/documentation/docs/components/landing-page.tsx b/documentation/docs/components/landing-page.tsx
index 699e704263..011ab24266 100644
--- a/documentation/docs/components/landing-page.tsx
+++ b/documentation/docs/components/landing-page.tsx
@@ -1,120 +1,504 @@
-import React from "react";
-import { Box, Grid, Typography } from "@mui/material";
-import useMediaQuery from "@mui/material/useMediaQuery";
-import { useTheme } from "@mui/material/styles";
-
-import Image from "next/image";
+import React, { useState, useEffect, useRef } from "react";
import Link from "next/link";
-import networkDocs from "../public/images/landing/Vector1.png";
-import developerDocs from "../public/images/landing/Vector2.png";
-import sdkDocs from "../public/images/landing/Vector3.png";
-import operatorGuide from "../public/images/landing/Vector4.png";
-export const LandingPage = () => {
- const theme = useTheme();
- const isTablet = useMediaQuery(theme.breakpoints.up("md"));
- const isDesktop = useMediaQuery(theme.breakpoints.up("xl"));
+const asciiStyle: React.CSSProperties = {
+ fontFamily: "var(--font-mono)",
+ fontSize: "0.72rem",
+ lineHeight: 1.4,
+ color: "var(--colorPrimary)",
+ opacity: 0.7,
+ whiteSpace: "pre",
+ margin: 0,
+};
- const squares = [
- {
- text: "Network Docs",
- description: "Architecture, crypto systems, and how the Mixnet works",
- href: "/network",
- icon: developerDocs,
- },
- {
- text: "Operator Guides",
- description:
- "Guides and maintenance: if you want to run a node, start here",
+// ── Animation components ──
- href: "/operators/introduction",
- icon: operatorGuide,
- },
- {
- text: "Developer Portal",
- description: "Conceptual overview, clients, tools and SDKs",
+const randomRow = () => Math.floor(Math.random() * 3);
+const randomPath = () => [randomRow(), randomRow(), randomRow()];
- href: "/developers",
- icon: sdkDocs,
- },
- {
- text: "APIs",
- description: "Interactive API specs for Nym infrastructure",
+const NetworkAnimation = () => {
+ // Packets traverse 5 stages: gw_e(0) → M1(1) → M2(2) → M3(3) → gw_ex(4)
+ // stage -1 = not yet mounted (SSR-safe, renders all ○)
+ const [packets, setPackets] = useState([
+ { path: randomPath(), stage: -1 },
+ { path: randomPath(), stage: -1 },
+ ]);
+ useEffect(() => {
+ // kick off with staggered positions
+ setPackets([
+ { path: randomPath(), stage: 0 },
+ { path: randomPath(), stage: 3 },
+ ]);
- href: "/apis/introduction",
- icon: networkDocs,
- },
- ];
+ const id = setInterval(() => {
+ setPackets((prev) =>
+ prev.map((p) => {
+ const next = (p.stage + 1) % 5;
+ return { stage: next, path: next === 0 ? randomPath() : p.path };
+ })
+ );
+ }, 300);
+ return () => clearInterval(id);
+ }, []);
- const shortenDescription = (description: string) => {
- return description.slice(0, 18) + "...";
+ const gwNode = (stage: number) => {
+ const active = packets.some((p) => p.stage === stage);
+ return (
+
+ {active ? "\u25CF" : "\u25CB"}
+
+ );
+ };
+
+ const mixNode = (col: number, row: number) => {
+ const active = packets.some(
+ (p) => p.stage === col + 1 && p.path[col] === row
+ );
+ const filled = active;
+ return (
+
+ {filled ? "\u25CF" : "\u25CB"}
+
+ );
};
return (
-
- {/*
- Nym Docs
-
-
-
- Nym is a privacy platform. It provides strong network-level privacy
- against sophisticated end-to-end attackers, and anonymous access control
- using blinded, re-randomizable, decentralized credentials. Our goal is
- to allow developers to build new applications, or upgrade existing apps,
- with privacy features unavailable in other systems.
- */}
-
- {squares.map((square, index) => (
-
-
-
-
- {square.text}
-
-
-
- {square.description}
-
-
-
-
-
-
- ))}
-
-
+
+ {"gw_e M1 M2 M3 gw_ex\n"}
+ {" "}
+ {mixNode(0, 0)}
+ {" \u2500\u2500 "}
+ {mixNode(1, 0)}
+ {" \u2500\u2500 "}
+ {mixNode(2, 0)}
+ {"\n"}
+ {" \\ / \\ /\n"}
+ {" "}
+ {gwNode(0)}
+ {" \u2500\u2500 "}
+ {mixNode(0, 1)}
+ {" \u2500\u2500 "}
+ {mixNode(1, 1)}
+ {" \u2500\u2500 "}
+ {mixNode(2, 1)}
+ {" \u2500\u2500 "}
+ {gwNode(4)}
+ {"\n"}
+ {" / \\ / \\\n"}
+ {" "}
+ {mixNode(0, 2)}
+ {" \u2500\u2500 "}
+ {mixNode(1, 2)}
+ {" \u2500\u2500 "}
+ {mixNode(2, 2)}
+
+ );
+};
+
+const TypewriterAnimation = () => {
+ const text =
+ "let client = MixnetClient::connect_new().await?;\n" +
+ "\n" +
+ "client.send(msg).await;";
+ const [charCount, setCharCount] = useState(0);
+ const [showCursor, setShowCursor] = useState(true);
+
+ useEffect(() => {
+ let cancelled = false;
+ const run = () => {
+ setCharCount(0);
+ let i = 0;
+ const type = () => {
+ if (cancelled) return;
+ if (i <= text.length) {
+ setCharCount(i);
+ i++;
+ setTimeout(type, 40);
+ } else {
+ setTimeout(() => {
+ if (!cancelled) run();
+ }, 2000);
+ }
+ };
+ type();
+ };
+ run();
+ return () => {
+ cancelled = true;
+ };
+ }, []);
+
+ useEffect(() => {
+ const id = setInterval(() => setShowCursor((v) => !v), 530);
+ return () => clearInterval(id);
+ }, []);
+
+ return (
+
+ {text.slice(0, charCount)}
+ {showCursor ? "\u258C" : " "}
+ {text.slice(charCount)}
+
+ );
+};
+
+const OperatorsAnimation = () => {
+ const totalBars = 10;
+ const [tick, setTick] = useState(0);
+ const mixRef = useRef(0);
+ const [mixCount, setMixCount] = useState(0);
+
+ useEffect(() => {
+ const id = setInterval(() => {
+ setTick((t) => t + 1);
+ mixRef.current += Math.floor(Math.random() * 8) + 5;
+ setMixCount(mixRef.current);
+ }, 80);
+ return () => clearInterval(id);
+ }, []);
+
+ const mixFilled = Math.min(tick % 12, totalBars);
+ const bar = (f: number) =>
+ "\u25A0".repeat(f) + "\u25A1".repeat(totalBars - f);
+ const fmt = (n: number) => n.toLocaleString("en");
+
+ return (
+
+ {"> nym-node run\n\n"}
+ {" mixing: "}
+ {bar(mixFilled)}
+ {" "}
+ {fmt(mixCount)}
+ {" pkts"}
+
+ );
+};
+
+const ApiAnimation = () => {
+ const lines = [
+ "GET /v1/mixnodes/active",
+ "",
+ '{ "count": 498,',
+ ' "nodes": [ ... ] }',
+ ];
+ const [visibleLines, setVisibleLines] = useState(0);
+
+ useEffect(() => {
+ let cancelled = false;
+ const run = () => {
+ setVisibleLines(0);
+ setTimeout(() => {
+ if (cancelled) return;
+ setVisibleLines(1);
+ setTimeout(() => {
+ if (cancelled) return;
+ let i = 2;
+ const reveal = () => {
+ if (cancelled) return;
+ if (i <= lines.length) {
+ setVisibleLines(i);
+ i++;
+ setTimeout(reveal, 300);
+ } else {
+ setTimeout(() => {
+ if (!cancelled) run();
+ }, 2000);
+ }
+ };
+ reveal();
+ }, 800);
+ }, 100);
+ };
+ run();
+ return () => {
+ cancelled = true;
+ };
+ }, []);
+
+ return (
+
+ {lines.slice(0, visibleLines).map((line, i) => (
+
+ {i > 0 && "\n"}
+ {line}
+
+ ))}
+
+ {lines.slice(visibleLines).map((line, i) => (
+
+ {visibleLines > 0 || i > 0 ? "\n" : ""}
+ {line}
+
+ ))}
+
+
+ );
+};
+
+// ── Section data ──
+
+const sections = [
+ {
+ title: "Network",
+ description:
+ "Architecture, cryptographic systems, and how the Mixnet protects your traffic.",
+ href: "/network",
+ animation: "network" as const,
+ },
+ {
+ title: "Developers",
+ description: "SDKs, tutorials, and integration guides for building on Nym.",
+ href: "/developers",
+ animation: "typewriter" as const,
+ },
+ {
+ title: "Operators",
+ description:
+ "Set up and maintain mix nodes, gateways, and network infrastructure.",
+ href: "/operators/introduction",
+ animation: "progress" as const,
+ },
+ {
+ title: "APIs",
+ description: "Interactive specs for querying Nym infrastructure.",
+ href: "/apis/introduction",
+ animation: "api" as const,
+ },
+];
+
+const AnimationBlock = ({ type }: { type: string }) => {
+ switch (type) {
+ case "network":
+ return ;
+ case "typewriter":
+ return ;
+ case "progress":
+ return ;
+ case "api":
+ return ;
+ default:
+ return null;
+ }
+};
+
+const sdks = [
+ {
+ name: "Rust",
+ description:
+ "Native SDK with async Mixnet client, streams, and TcpProxy modules.",
+ href: "/developers/rust",
+ },
+ {
+ name: "TypeScript",
+ description:
+ "Browser-based SDK with fetch API replacement and message-based WebSocket transport.",
+ href: "/developers/typescript",
+ },
+];
+
+export const LandingPage = () => {
+ return (
+
+ {/* ── Section cards ── */}
+
+ {sections.map((s, i) => (
+
+
+
+
+
+ {s.title}
+
+
+ ›
+
+
+
+ {s.description}
+
+
+
+
+
+ ))}
+
+
+ {/* ── SDKs ── */}
+
+
+
+ SDKs
+
+
+ Integrate Mixnet privacy into your application with our Rust and
+ TypeScript SDKs.
+
+
+
+ {sdks.map((sdk, i) => (
+
+
0 ? "-1px" : undefined,
+ display: "flex",
+ alignItems: "center",
+ justifyContent: "space-between",
+ transition: "background-color 0.15s",
+ cursor: "pointer",
+ }}
+ >
+
+
+ {sdk.name}
+
+
+ {sdk.description}
+
+
+
+ ›
+
+
+
+ ))}
+
+
+
+ {/* ── Links ── */}
+
+
);
};
diff --git a/documentation/docs/components/outputs/api-scraping-outputs/time-now.md b/documentation/docs/components/outputs/api-scraping-outputs/time-now.md
index d0e186efdb..597096bfa2 100644
--- a/documentation/docs/components/outputs/api-scraping-outputs/time-now.md
+++ b/documentation/docs/components/outputs/api-scraping-outputs/time-now.md
@@ -1 +1 @@
-Wednesday, March 18th 2026, 14:02:49 UTC
+Tuesday, March 24th 2026, 13:05:57 UTC
diff --git a/documentation/docs/components/outputs/command-outputs/nym-node-run-help.md b/documentation/docs/components/outputs/command-outputs/nym-node-run-help.md
index f10b058c61..b3e26b1f56 100644
--- a/documentation/docs/components/outputs/command-outputs/nym-node-run-help.md
+++ b/documentation/docs/components/outputs/command-outputs/nym-node-run-help.md
@@ -4,109 +4,86 @@ Start this nym-node
Usage: nym-node run [OPTIONS]
Options:
- --id
- Id of the nym-node to use [env: NYMNODE_ID=] [default: default-nym-node]
- --config-file
- Path to a configuration file of this node [env: NYMNODE_CONFIG=]
- --accept-operator-terms-and-conditions
- Explicitly specify whether you agree with the terms and conditions of a nym node operator as defined at [env:
- NYMNODE_ACCEPT_OPERATOR_TERMS=]
- --deny-init
- Forbid a new node from being initialised if configuration file for the provided specification doesn't already exist [env: NYMNODE_DENY_INIT=]
- --init-only
- If this is a brand new nym-node, specify whether it should only be initialised without actually running the subprocesses [env: NYMNODE_INIT_ONLY=]
- --local
- Flag specifying this node will be running in a local setting [env: NYMNODE_LOCAL=]
- --mode [...]
- Specifies the current mode(s) of this nym-node [env: NYMNODE_MODE=] [possible values: mixnode, entry-gateway, exit-gateway, exit-providers-only]
- --modes
- Specifies the current mode(s) of this nym-node as a single flag [env: NYMNODE_MODES=] [possible values: mixnode, entry-gateway, exit-gateway, exit-providers-only]
- -w, --write-changes
- If this node has been initialised before, specify whether to write any new changes to the config file [env: NYMNODE_WRITE_CONFIG_CHANGES=]
- --bonding-information-output
- Specify output file for bonding information of this nym-node, i.e. its encoded keys. NOTE: the required bonding information is still a subject to change and this argument should be
- treated only as a preview of future features [env: NYMNODE_BONDING_INFORMATION_OUTPUT=]
- -o, --output
- Specify the output format of the bonding information (`text` or `json`) [env: NYMNODE_OUTPUT=] [default: text] [possible values: text, json]
- --public-ips
- Comma separated list of public ip addresses that will be announced to the nym-api and subsequently to the clients. In nearly all circumstances, it's going to be identical to the
- address you're going to use for bonding [env: NYMNODE_PUBLIC_IPS=]
- --hostname
- Optional hostname associated with this gateway that will be announced to the nym-api and subsequently to the clients [env: NYMNODE_HOSTNAME=]
- --location
- Optional **physical** location of this node's server. Either full country name (e.g. 'Poland'), two-letter alpha2 (e.g. 'PL'), three-letter alpha3 (e.g. 'POL') or three-digit
- numeric-3 (e.g. '616') can be provided [env: NYMNODE_LOCATION=]
- --http-bind-address
- Socket address this node will use for binding its http API. default: `[::]:8080` [env: NYMNODE_HTTP_BIND_ADDRESS=]
- --landing-page-assets-path
- Path to assets directory of custom landing page of this node [env: NYMNODE_HTTP_LANDING_ASSETS=]
- --http-access-token
- An optional bearer token for accessing certain http endpoints. Currently only used for prometheus metrics [env: NYMNODE_HTTP_ACCESS_TOKEN=]
- --expose-system-info
- Specify whether basic system information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_SYSTEM_INFO=] [possible values: true, false]
- --expose-system-hardware
- Specify whether basic system hardware information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_SYSTEM_HARDWARE=] [possible values: true, false]
- --expose-crypto-hardware
- Specify whether detailed system crypto hardware information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_CRYPTO_HARDWARE=] [possible values: true, false]
- --mixnet-bind-address
- Address this node will bind to for listening for mixnet packets default: `[::]:1789` [env: NYMNODE_MIXNET_BIND_ADDRESS=]
- --mixnet-announce-port
- If applicable, custom port announced in the self-described API that other clients and nodes will use. Useful when the node is behind a proxy [env: NYMNODE_MIXNET_ANNOUNCE_PORT=]
- --nym-api-urls
- Addresses to nym APIs from which the node gets the view of the network [env: NYMNODE_NYM_APIS=]
- --nyxd-urls
- Addresses to nyxd chain endpoint which the node will use for chain interactions [env: NYMNODE_NYXD=]
- --enable-console-logging
- Specify whether running statistics of this node should be logged to the console [env: NYMNODE_ENABLE_CONSOLE_LOGGING=] [possible values: true, false]
- --wireguard-enabled
- Specifies whether the wireguard service is enabled on this node [env: NYMNODE_WG_ENABLED=] [possible values: true, false]
- --wireguard-bind-address
- Socket address this node will use for binding its wireguard interface. default: `[::]:51822` [env: NYMNODE_WG_BIND_ADDRESS=]
- --wireguard-tunnel-announced-port
- Tunnel port announced to external clients wishing to connect to the wireguard interface. Useful in the instances where the node is behind a proxy [env: NYMNODE_WG_ANNOUNCED_PORT=]
- --wireguard-private-network-prefix
- The prefix denoting the maximum number of the clients that can be connected via Wireguard. The maximum value for IPv4 is 32 and for IPv6 is 128 [env:
- NYMNODE_WG_PRIVATE_NETWORK_PREFIX=]
- --wireguard-userspace
- Use userspace implementation of WireGuard (wireguard-go) instead of kernel module. Useful in containerized environments without kernel WireGuard support [env: NYMNODE_WG_USERSPACE=]
- [possible values: true, false]
- --verloc-bind-address
- Socket address this node will use for binding its verloc API. default: `[::]:1790` [env: NYMNODE_VERLOC_BIND_ADDRESS=]
- --verloc-announce-port
- If applicable, custom port announced in the self-described API that other clients and nodes will use. Useful when the node is behind a proxy [env: NYMNODE_VERLOC_ANNOUNCE_PORT=]
- --entry-bind-address
- Socket address this node will use for binding its client websocket API. default: `[::]:9000` [env: NYMNODE_ENTRY_BIND_ADDRESS=]
- --announce-ws-port
- Custom announced port for listening for websocket client traffic. If unspecified, the value from the `bind_address` will be used instead [env: NYMNODE_ENTRY_ANNOUNCE_WS_PORT=]
- --announce-wss-port
- If applicable, announced port for listening for secure websocket client traffic [env: NYMNODE_ENTRY_ANNOUNCE_WSS_PORT=]
- --enforce-zk-nyms
- Indicates whether this gateway is accepting only coconut credentials for accessing the mixnet or if it also accepts non-paying clients [env: NYMNODE_ENFORCE_ZK_NYMS=] [possible
- values: true, false]
- --mnemonic
- Custom cosmos wallet mnemonic used for zk-nym redemption. If no value is provided, a fresh mnemonic is going to be generated [env: NYMNODE_MNEMONIC=]
- --upgrade-mode-attestation-url
- Endpoint to query to retrieve current upgrade mode attestation. This argument should never be set outside testnets and local networks [env: NYMNODE_UPGRADE_MODE_ATTESTATION_URL=]
- --upgrade-mode-attester-public-key
- Expected public key of the entity signing the published attestation. This argument should never be set outside testnets and local networks [env:
- NYMNODE_UPGRADE_MODE_ATTESTER_PUBKEY=]
- --upstream-exit-policy-url
- Specifies the url for an upstream source of the exit policy used by this node [env: NYMNODE_UPSTREAM_EXIT_POLICY=]
- --open-proxy
- Specifies whether this exit node should run in 'open-proxy' mode and thus would attempt to resolve **ANY** request it receives [env: NYMNODE_OPEN_PROXY=] [possible values: true,
- false]
- --lp-control-bind-address
- Bind address for the TCP LP control traffic. default: `[::]:41264` [env: NYMNODE_LP_CONTROL_BIND_ADDRESS=]
- --lp-control-announce-port
- Custom announced port for listening for the TCP LP control traffic. If unspecified, the value from the `lp_control_bind_address` will be used instead [env:
- NYMNODE_LP_CONTROL_ANNOUNCE_PORT=]
- --lp-data-bind-address
- Bind address for the UDP LP data traffic. default: `[::]:51264` [env: NYMNODE_LP_DATA_BIND_ADDRESS=]
- --lp-data-announce-port
- Custom announced port for listening for the UDP LP data traffic. If unspecified, the value from the `lp_data_bind_address` will be used instead [env: NYMNODE_LP_DATA_ANNOUNCE_PORT=]
- --lp-use-mock-ecash
- Use mock ecash manager for LP testing. WARNING: Only use this for local testing! Never enable in production. When enabled, the LP listener will accept any credential without
- blockchain verification [env: NYMNODE_LP_USE_MOCK_ECASH=] [possible values: true, false]
- -h, --help
- Print help
+ --id Id of the nym-node to use [env: NYMNODE_ID=] [default: default-nym-node]
+ --config-file Path to a configuration file of this node [env: NYMNODE_CONFIG=]
+ --accept-operator-terms-and-conditions Explicitly specify whether you agree with the terms and conditions of a nym node operator as defined at
+ [env: NYMNODE_ACCEPT_OPERATOR_TERMS=]
+ --deny-init Forbid a new node from being initialised if configuration file for the provided specification doesn't already exist [env:
+ NYMNODE_DENY_INIT=]
+ --init-only If this is a brand new nym-node, specify whether it should only be initialised without actually running the subprocesses
+ [env: NYMNODE_INIT_ONLY=]
+ --local Flag specifying this node will be running in a local setting [env: NYMNODE_LOCAL=]
+ --mode [...] Specifies the current mode(s) of this nym-node [env: NYMNODE_MODE=] [possible values: mixnode, entry-gateway,
+ exit-gateway, exit-providers-only]
+ --modes Specifies the current mode(s) of this nym-node as a single flag [env: NYMNODE_MODES=] [possible values: mixnode,
+ entry-gateway, exit-gateway, exit-providers-only]
+ -w, --write-changes If this node has been initialised before, specify whether to write any new changes to the config file [env:
+ NYMNODE_WRITE_CONFIG_CHANGES=]
+ --bonding-information-output Specify output file for bonding information of this nym-node, i.e. its encoded keys. NOTE: the required bonding
+ information is still a subject to change and this argument should be treated only as a preview of future features [env:
+ NYMNODE_BONDING_INFORMATION_OUTPUT=]
+ -o, --output Specify the output format of the bonding information (`text` or `json`) [env: NYMNODE_OUTPUT=] [default: text] [possible
+ values: text, json]
+ --public-ips Comma separated list of public ip addresses that will be announced to the nym-api and subsequently to the clients. In
+ nearly all circumstances, it's going to be identical to the address you're going to use for bonding [env:
+ NYMNODE_PUBLIC_IPS=]
+ --hostname Optional hostname associated with this gateway that will be announced to the nym-api and subsequently to the clients [env:
+ NYMNODE_HOSTNAME=]
+ --location Optional **physical** location of this node's server. Either full country name (e.g. 'Poland'), two-letter alpha2 (e.g.
+ 'PL'), three-letter alpha3 (e.g. 'POL') or three-digit numeric-3 (e.g. '616') can be provided [env: NYMNODE_LOCATION=]
+ --http-bind-address Socket address this node will use for binding its http API. default: `[::]:8080` [env: NYMNODE_HTTP_BIND_ADDRESS=]
+ --landing-page-assets-path Path to assets directory of custom landing page of this node [env: NYMNODE_HTTP_LANDING_ASSETS=]
+ --http-access-token An optional bearer token for accessing certain http endpoints. Currently only used for prometheus metrics [env:
+ NYMNODE_HTTP_ACCESS_TOKEN=]
+ --expose-system-info Specify whether basic system information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_SYSTEM_INFO=]
+ [possible values: true, false]
+ --expose-system-hardware Specify whether basic system hardware information should be exposed. default: true [env:
+ NYMNODE_HTTP_EXPOSE_SYSTEM_HARDWARE=] [possible values: true, false]
+ --expose-crypto-hardware Specify whether detailed system crypto hardware information should be exposed. default: true [env:
+ NYMNODE_HTTP_EXPOSE_CRYPTO_HARDWARE=] [possible values: true, false]
+ --mixnet-bind-address Address this node will bind to for listening for mixnet packets default: `[::]:1789` [env: NYMNODE_MIXNET_BIND_ADDRESS=]
+ --mixnet-announce-port If applicable, custom port announced in the self-described API that other clients and nodes will use. Useful when the node
+ is behind a proxy [env: NYMNODE_MIXNET_ANNOUNCE_PORT=]
+ --nym-api-urls Addresses to nym APIs from which the node gets the view of the network [env: NYMNODE_NYM_APIS=]
+ --nyxd-urls Addresses to nyxd chain endpoint which the node will use for chain interactions [env: NYMNODE_NYXD=]
+ --enable-console-logging Specify whether running statistics of this node should be logged to the console [env: NYMNODE_ENABLE_CONSOLE_LOGGING=]
+ [possible values: true, false]
+ --wireguard-enabled Specifies whether the wireguard service is enabled on this node [env: NYMNODE_WG_ENABLED=] [possible values: true, false]
+ --wireguard-bind-address Socket address this node will use for binding its wireguard interface. default: `[::]:51822` [env:
+ NYMNODE_WG_BIND_ADDRESS=]
+ --wireguard-tunnel-announced-port Tunnel port announced to external clients wishing to connect to the wireguard interface. Useful in the instances where the
+ node is behind a proxy [env: NYMNODE_WG_ANNOUNCED_PORT=]
+ --wireguard-private-network-prefix The prefix denoting the maximum number of the clients that can be connected via Wireguard. The maximum value for IPv4 is
+ 32 and for IPv6 is 128 [env: NYMNODE_WG_PRIVATE_NETWORK_PREFIX=]
+ --wireguard-userspace Use userspace implementation of WireGuard (wireguard-go) instead of kernel module. Useful in containerized environments
+ without kernel WireGuard support [env: NYMNODE_WG_USERSPACE=] [possible values: true, false]
+ --verloc-bind-address Socket address this node will use for binding its verloc API. default: `[::]:1790` [env: NYMNODE_VERLOC_BIND_ADDRESS=]
+ --verloc-announce-port If applicable, custom port announced in the self-described API that other clients and nodes will use. Useful when the node
+ is behind a proxy [env: NYMNODE_VERLOC_ANNOUNCE_PORT=]
+ --entry-bind-address Socket address this node will use for binding its client websocket API. default: `[::]:9000` [env:
+ NYMNODE_ENTRY_BIND_ADDRESS=]
+ --announce-ws-port Custom announced port for listening for websocket client traffic. If unspecified, the value from the `bind_address` will
+ be used instead [env: NYMNODE_ENTRY_ANNOUNCE_WS_PORT=]
+ --announce-wss-port If applicable, announced port for listening for secure websocket client traffic [env: NYMNODE_ENTRY_ANNOUNCE_WSS_PORT=]
+ --enforce-zk-nyms Indicates whether this gateway is accepting only coconut credentials for accessing the mixnet or if it also accepts
+ non-paying clients [env: NYMNODE_ENFORCE_ZK_NYMS=] [possible values: true, false]
+ --mnemonic Custom cosmos wallet mnemonic used for zk-nym redemption. If no value is provided, a fresh mnemonic is going to be
+ generated [env: NYMNODE_MNEMONIC=]
+ --upgrade-mode-attestation-url Endpoint to query to retrieve current upgrade mode attestation. This argument should never be set outside testnets and
+ local networks [env: NYMNODE_UPGRADE_MODE_ATTESTATION_URL=]
+ --upgrade-mode-attester-public-key Expected public key of the entity signing the published attestation. This argument should never be set outside testnets
+ and local networks [env: NYMNODE_UPGRADE_MODE_ATTESTER_PUBKEY=]
+ --upstream-exit-policy-url Specifies the url for an upstream source of the exit policy used by this node [env: NYMNODE_UPSTREAM_EXIT_POLICY=]
+ --open-proxy Specifies whether this exit node should run in 'open-proxy' mode and thus would attempt to resolve **ANY** request it
+ receives [env: NYMNODE_OPEN_PROXY=] [possible values: true, false]
+ --lp-control-bind-address Bind address for the TCP LP control traffic. default: `[::]:41264` [env: NYMNODE_LP_CONTROL_BIND_ADDRESS=]
+ --lp-control-announce-port Custom announced port for listening for the TCP LP control traffic. If unspecified, the value from the
+ `lp_control_bind_address` will be used instead [env: NYMNODE_LP_CONTROL_ANNOUNCE_PORT=]
+ --lp-data-bind-address Bind address for the UDP LP data traffic. default: `[::]:51264` [env: NYMNODE_LP_DATA_BIND_ADDRESS=]
+ --lp-data-announce-port Custom announced port for listening for the UDP LP data traffic. If unspecified, the value from the `lp_data_bind_address`
+ will be used instead [env: NYMNODE_LP_DATA_ANNOUNCE_PORT=]
+ --lp-use-mock-ecash Use mock ecash manager for LP testing. WARNING: Only use this for local testing! Never enable in production. When enabled,
+ the LP listener will accept any credential without blockchain verification [env: NYMNODE_LP_USE_MOCK_ECASH=] [possible
+ values: true, false]
+ -h, --help Print help
```
diff --git a/documentation/docs/pages/_app.tsx b/documentation/docs/pages/_app.tsx
index f76d9a47ef..15e08f8a0a 100644
--- a/documentation/docs/pages/_app.tsx
+++ b/documentation/docs/pages/_app.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import React, { useMemo, useEffect } from 'react';
import type { AppProps } from 'next/app';
import './styles.css';
import { ThemeProvider, createTheme } from '@mui/material/styles';
@@ -20,6 +20,17 @@ const MyApp: React.FC = ({ Component, pageProps }) => {
}),
[],
);
+ useEffect(() => {
+ const handler = (e: MouseEvent) => {
+ const img = e.target as HTMLElement;
+ if (img.tagName === 'IMG' && img.closest('.nextra-content')) {
+ img.classList.toggle('img-expanded');
+ }
+ };
+ document.addEventListener('click', handler);
+ return () => document.removeEventListener('click', handler);
+ }, []);
+
const AnyComponent = Component as any;
return (
diff --git a/documentation/docs/pages/network/architecture.mdx b/documentation/docs/pages/network/architecture.mdx
index 19560c0bb2..a3b8086b9b 100644
--- a/documentation/docs/pages/network/architecture.mdx
+++ b/documentation/docs/pages/network/architecture.mdx
@@ -3,6 +3,4 @@
Core components:
* A **Mixnet**, which mixes Sphinx packet traffic so that it cannot be determined who is communicating with whom. Our mixnet is based on a modified version of the [**Loopix** design](concepts/loopix). This is made up of [Nym nodes](architecture/mixnet#nodes) runnning on servers around the world maintained by a decentralised group of Operators.
* Various [**Nym clients**](architecture/mixnet#nym-clients) which manage sending and receiving Sphinx packets, encrypting/decrypting traffic, and providing [cover traffic](./concepts/cover-traffic) to hide 'real' traffic timing.
-* A CosmWasm-enabled blockchain called [**Nyx**](architecture/nyx), the home of the various smart contracts used by the mixnet. A subset of Nyx Validators run [NymAPI](./architecture/nyx#nymapi) instances, taking part in also producing and verifying [zk-nym credentials](cryptography/zk-nym).
-
-
+* A CosmWasm-enabled blockchain called [**Nyx**](architecture/nyx), the home of the various smart contracts used by the mixnet. A subset of Nyx Validators run [NymAPI](./architecture/nyx#nymapi) instances, taking part in also producing and verifying [zk-nym credentials](cryptography/zk-nym).
\ No newline at end of file
diff --git a/documentation/docs/pages/styles.css b/documentation/docs/pages/styles.css
index 0e5c829a30..1de040d5d1 100644
--- a/documentation/docs/pages/styles.css
+++ b/documentation/docs/pages/styles.css
@@ -1,21 +1,67 @@
-/* nym.com-aligned colour tokens */
-:root {
- --colorPrimary: #85E89D;
- --textPrimary: #FFFFFF;
- --bg-dark: #1E2426;
- --border-dark: #2E3538;
+/* nym docs – angular, clean styling (oxide-inspired) */
+
+@font-face {
+ font-family: 'JetBrains Mono';
+ src: url('/docs/fonts/JetBrainsMono-Regular.woff2') format('woff2');
+ font-weight: 400;
+ font-style: normal;
+ font-display: swap;
}
-/* dark mode background override */
+@font-face {
+ font-family: 'JetBrains Mono';
+ src: url('/docs/fonts/JetBrainsMono-Medium.woff2') format('woff2');
+ font-weight: 500;
+ font-style: normal;
+ font-display: swap;
+}
+
+@font-face {
+ font-family: 'JetBrains Mono';
+ src: url('/docs/fonts/JetBrainsMono-SemiBold.woff2') format('woff2');
+ font-weight: 600;
+ font-style: normal;
+ font-display: swap;
+}
+
+@font-face {
+ font-family: 'JetBrains Mono';
+ src: url('/docs/fonts/JetBrainsMono-Bold.woff2') format('woff2');
+ font-weight: 700;
+ font-style: normal;
+ font-display: swap;
+}
+
+:root {
+ --colorPrimary: #85E89D;
+ --textPrimary: #E0E0E0;
+ --textMuted: #8B9295;
+ --bg-dark: #181C1E;
+ --bg-code: #1C2022;
+ --border-dark: #2A2F32;
+ --border: #2A2F32;
+ --font-mono: 'JetBrains Mono', 'SFMono-Regular', 'Consolas', 'Liberation Mono', 'Menlo', monospace;
+}
+
+/* ── Global: kill all rounded corners ── */
+
+*,
+*::before,
+*::after {
+ border-radius: 0 !important;
+}
+
+/* ── Dark mode backgrounds ── */
+
html.dark {
background-color: var(--bg-dark);
}
html.dark body {
background-color: var(--bg-dark);
+ color: var(--textPrimary);
}
-/* nextra main content area bg */
html.dark .nextra-nav-container,
html.dark .nextra-sidebar-container,
html.dark .nextra-content,
@@ -24,28 +70,43 @@ html.dark .dark\:nx-bg-dark {
background-color: var(--bg-dark) !important;
}
+/* ── Typography ── */
+
+h1, h2, h3, h4, h5, h6 {
+ font-family: var(--font-mono);
+ letter-spacing: -0.02em;
+ font-weight: 600;
+}
+
+html.dark h1 {
+ color: #FFFFFF;
+ font-weight: 700;
+}
+
+html.dark h2 {
+ color: #F0F0F0;
+ padding-bottom: 0.3em;
+ border-bottom: 1px solid var(--border-dark);
+}
+
+html.dark p, html.dark li {
+ color: var(--textPrimary);
+ line-height: 1.7;
+}
+
+/* ── Layout ── */
+
footer {
text-align: center;
}
.nextra-code-block > pre {
- /* max-height: 350px !important; */
max-height: none !important;
scroll-y: auto !important;
}
-/* set width entire div */
.nx-mx-auto.nx-flex.nx-max-w-\[90rem\] {
max-width: 110rem;
- left-padding: 1%;
-}
-
-.nextra-toc {
- width: 10px !important;
- padding-right: 0px;
- padding-left: 0px;
- /* text-align: right; */
- border-left: 1px solid var(--border-dark);
}
.nextra-content {
@@ -56,23 +117,26 @@ footer {
margin: 0 !important;
}
-:is(html[class~="dark"] .dark\:nx-bg-primary-300\/10) {
- background-color: hsl(var(black) 100% 77%/0.1) !important;
+/* ── Nav bar ── */
+
+html.dark .nextra-nav-container {
+ border-bottom: 1px solid var(--border-dark) !important;
}
-/* Sidebar active item */
-:is(html .dark\:nx-bg-primary-400\/10) {
- background: transparent !important;
- border-left: 2px solid #85E89D;
- color: #FFFFFF !important;
+html.dark .nextra-nav-container nav a,
+html.dark .nextra-nav-container nav button,
+html.dark .nextra-nav-container nav ul a {
+ font-family: var(--font-mono);
+ font-size: 0.85rem;
}
-:is(html:not(.dark) .dark\:nx-bg-primary-400\/10) {
- background: transparent !important;
- border-left: 2px solid #4A9E5C;
- color: #242B2D !important;
+html.dark .nextra-nav-container nav a:hover,
+html.dark .nextra-nav-container nav ul a:hover {
+ color: var(--colorPrimary) !important;
}
+/* ── Sidebar ── */
+
.nextra-sidebar-container {
border-right: 1px solid var(--border-dark);
width: 300px !important;
@@ -82,21 +146,171 @@ footer {
column-width: 500px;
}
-/* Links*/
+/* Sidebar font */
+html.dark .nextra-sidebar-container {
+ font-family: var(--font-mono);
+ font-size: 0.82rem;
+}
+
+/* Sidebar text: muted by default */
+html.dark .nextra-sidebar-container a {
+ color: var(--textMuted) !important;
+}
+
+html.dark .nextra-sidebar-container a:hover {
+ color: var(--textPrimary) !important;
+}
+
+/* Sidebar separator labels (not active items) */
+html.dark .nextra-sidebar-container li.nx-mt-5 .nx-font-semibold {
+ color: var(--textMuted) !important;
+ font-size: 0.7rem;
+ letter-spacing: 0.05em;
+}
+
+/* Active sidebar item: left-border accent + subtle tint */
+:is(html .dark\:nx-bg-primary-400\/10) {
+ background: rgba(133, 232, 157, 0.06) !important;
+ border-left: 2px solid var(--colorPrimary);
+ color: #FFFFFF !important;
+}
+
+html.dark .nextra-sidebar-container :is(.dark\:nx-bg-primary-400\/10) a {
+ color: #FFFFFF !important;
+}
+
+:is(html:not(.dark) .dark\:nx-bg-primary-400\/10) {
+ background: rgba(74, 158, 92, 0.08) !important;
+ border-left: 2px solid #4A9E5C;
+ color: #242B2D !important;
+}
+
+:is(html[class~="dark"] .dark\:nx-bg-primary-300\/10) {
+ background-color: transparent !important;
+}
+
+/* ── TOC (hidden — subsections live in sidebar) ── */
+
+.nextra-toc {
+ display: none !important;
+}
+
+/* ── Code blocks ── */
+
+html.dark .nextra-code-block > pre {
+ background-color: var(--bg-code) !important;
+ border: 1px solid var(--border-dark);
+}
+
+/* Language tag in code blocks */
+html.dark .nextra-code-block [class*="nx-absolute"] {
+ color: var(--textMuted);
+ font-size: 0.7rem;
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+}
+
+/* Inline code: subtle background, no border */
+html.dark code:not(pre code) {
+ background-color: rgba(255, 255, 255, 0.06) !important;
+ border: none !important;
+ padding: 0.15em 0.4em;
+ font-size: 0.88em;
+ color: var(--textPrimary);
+}
+
+/* ── Callouts: left-border accent ── */
+
+html.dark .nextra-callout {
+ border: none;
+ border-left: 3px solid;
+ background: rgba(255, 255, 255, 0.02);
+}
+
+/* ── Tables: monospace uppercase headers ── */
+
+html.dark table {
+ border-collapse: collapse;
+ width: 100%;
+}
+
+html.dark th {
+ border-bottom: 1px solid var(--border-dark);
+ text-align: left;
+ font-weight: 600;
+ font-family: var(--font-mono);
+ font-size: 0.75rem;
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+ color: var(--textMuted);
+ padding: 0.6em 1em;
+}
+
+html.dark td {
+ border-bottom: 1px solid var(--border-dark);
+ padding: 0.6em 1em;
+ color: var(--textPrimary);
+}
+
+html.dark tr:hover td {
+ background-color: rgba(255, 255, 255, 0.02);
+}
+
+/* ── Search box ── */
+
+html.dark .nextra-search input {
+ border: 1px solid var(--border-dark);
+ background-color: var(--bg-dark) !important;
+ color: var(--textMuted);
+ font-family: var(--font-mono);
+ font-size: 0.8rem;
+}
+
+html.dark .nextra-search input::placeholder {
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+ font-size: 0.72rem;
+}
+
+/* ── Links ── */
+
.nx-text-primary-600.nx-underline.nx-decoration-from-font {
color: var(--colorPrimary) !important;
}
-.MuiTypography-root.MuiTypography-inherit.MuiLink-root.MuiLink-underlineAlways.css-1xr3c94-MuiTypography-root-MuiLink-root {
+.nx-text-primary-600 {
+ color: var(--colorPrimary) !important;
+}
+
+.nextra-scrollbar.nx-sticky {
+ color: var(--colorPrimary) !important;
+}
+
+/* ── Breadcrumbs / navigation links ── */
+
+html.dark .nextra-breadcrumb {
+ color: var(--textMuted);
+}
+
+/* Prev/next page links */
+html.dark a.nx-flex.nx-items-center {
+ border-color: var(--border-dark) !important;
+}
+
+html.dark a.nx-flex.nx-items-center:hover {
+ border-color: var(--colorPrimary) !important;
+}
+
+/* ── Material UI overrides ── */
+
+.MuiTypography-root.MuiTypography-inherit.MuiLink-root.MuiLink-underlineAlways {
color: var(--colorPrimary) !important;
}
-/* Chips*/
.chipContained {
background-color: var(--colorPrimary) !important;
}
-/* Buttons */
.MuiButton-root {
color: var(--colorPrimary) !important;
border-color: var(--colorPrimary) !important;
@@ -111,11 +325,7 @@ footer {
color: var(--colorPrimary) !important;
}
-.nextra-scrollbar.nx-sticky {
- color: var(--colorPrimary) !important;
-}
-
-.nx-text-primary-600 {
+a.MuiLink-root {
color: var(--colorPrimary) !important;
}
@@ -127,10 +337,167 @@ input:focus-visible {
border-color: var(--colorPrimary) !important;
}
-a.MuiLink-root {
- color: var(--colorPrimary) !important;
+.MuiPaper-root.MuiAccordion-root {
+ border-radius: 0;
}
-.MuiPaper-root.MuiAccordion-root {
- border-radius: 8px;
+/* ── Landing page ── */
+
+.landing-heading {
+ color: #FFFFFF;
+}
+
+.landing-card:hover {
+ background-color: rgba(255, 255, 255, 0.03) !important;
+}
+
+/* ── Invert diagrams in dark mode ── */
+
+html.dark .nextra-content img:not([src*="landing"]) {
+ filter: invert(1) hue-rotate(180deg) brightness(0.92) contrast(1.1);
+ mix-blend-mode: lighten;
+ cursor: zoom-in;
+}
+
+/* Expanded image overlay */
+.nextra-content img.img-expanded {
+ position: fixed !important;
+ top: 0;
+ left: 0;
+ width: 100vw !important;
+ height: 100vh !important;
+ max-width: none !important;
+ object-fit: contain;
+ background: rgba(0, 0, 0, 0.9);
+ z-index: 9999;
+ cursor: zoom-out;
+ padding: 2rem;
+ mix-blend-mode: normal;
+ filter: none;
+}
+
+html.dark .nextra-content img.img-expanded {
+ filter: invert(1) hue-rotate(180deg) brightness(0.92) contrast(1.1);
+ mix-blend-mode: normal;
+}
+
+/* ── Light mode ── */
+
+html:not(.dark) {
+ --colorPrimary: #1a7a32;
+ --colorPrimary-light: #1a7a32;
+ --bg-light: #F5F5F5;
+ --border-light: #E0E0E0;
+ --border: #E0E0E0;
+ --textMuted: #6B7280;
+ --textMuted-light: #6B7280;
+}
+
+html:not(.dark) body {
+ background-color: var(--bg-light);
+}
+
+html:not(.dark) .nextra-nav-container,
+html:not(.dark) .nextra-sidebar-container,
+html:not(.dark) .nextra-content,
+html:not(.dark) .nx-bg-white {
+ background-color: var(--bg-light) !important;
+}
+
+/* Light mode links: darker green */
+html:not(.dark) .nx-text-primary-600 {
+ color: var(--colorPrimary-light) !important;
+}
+
+html:not(.dark) .nx-text-primary-600.nx-underline.nx-decoration-from-font {
+ color: var(--colorPrimary-light) !important;
+}
+
+/* Light mode sidebar */
+html:not(.dark) .nextra-sidebar-container {
+ font-family: var(--font-mono);
+ font-size: 0.82rem;
+ border-right: 1px solid var(--border-light);
+}
+
+html:not(.dark) .nextra-sidebar-container a {
+ color: var(--textMuted-light) !important;
+}
+
+html:not(.dark) .nextra-sidebar-container a:hover {
+ color: #111 !important;
+}
+
+/* Light mode nav */
+html:not(.dark) .nextra-nav-container {
+ border-bottom: 1px solid var(--border-light) !important;
+}
+
+html:not(.dark) .nextra-nav-container nav a,
+html:not(.dark) .nextra-nav-container nav button,
+html:not(.dark) .nextra-nav-container nav ul a {
+ font-family: var(--font-mono);
+ font-size: 0.85rem;
+}
+
+html:not(.dark) .nextra-nav-container nav a:hover,
+html:not(.dark) .nextra-nav-container nav ul a:hover {
+ color: var(--colorPrimary-light) !important;
+}
+
+/* Light mode code */
+html:not(.dark) code:not(pre code) {
+ background-color: rgba(0, 0, 0, 0.05) !important;
+ border: none !important;
+ padding: 0.15em 0.4em;
+ font-size: 0.88em;
+}
+
+/* Light mode callouts */
+html:not(.dark) .nextra-callout {
+ border: none;
+ border-left: 3px solid;
+ background: rgba(0, 0, 0, 0.02);
+}
+
+/* Light mode tables */
+html:not(.dark) th {
+ font-family: var(--font-mono);
+ font-size: 0.75rem;
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+ color: var(--textMuted-light);
+}
+
+/* Light mode search */
+html:not(.dark) .nextra-search input {
+ font-family: var(--font-mono);
+ font-size: 0.8rem;
+ border: 1px solid var(--border-light);
+ background-color: #FFFFFF !important;
+}
+
+html:not(.dark) .nextra-search input::placeholder {
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+ font-size: 0.72rem;
+}
+
+/* Light mode h2 border */
+html:not(.dark) h2 {
+ padding-bottom: 0.3em;
+ border-bottom: 1px solid var(--border-light);
+}
+
+/* Light mode landing page */
+html:not(.dark) .landing-heading {
+ color: #1a1a1a !important;
+}
+
+html:not(.dark) .landing-card:hover {
+ background-color: rgba(0, 0, 0, 0.02) !important;
+}
+
+html:not(.dark) .landing-card {
+ border-color: var(--border-light) !important;
}
diff --git a/documentation/docs/public/fonts/JetBrainsMono-Bold.woff2 b/documentation/docs/public/fonts/JetBrainsMono-Bold.woff2
new file mode 100644
index 0000000000..4917f43410
Binary files /dev/null and b/documentation/docs/public/fonts/JetBrainsMono-Bold.woff2 differ
diff --git a/documentation/docs/public/fonts/JetBrainsMono-LICENSE.txt b/documentation/docs/public/fonts/JetBrainsMono-LICENSE.txt
new file mode 100644
index 0000000000..8bee4148c1
--- /dev/null
+++ b/documentation/docs/public/fonts/JetBrainsMono-LICENSE.txt
@@ -0,0 +1,93 @@
+Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+https://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/documentation/docs/public/fonts/JetBrainsMono-Medium.woff2 b/documentation/docs/public/fonts/JetBrainsMono-Medium.woff2
new file mode 100644
index 0000000000..669d04cdf2
Binary files /dev/null and b/documentation/docs/public/fonts/JetBrainsMono-Medium.woff2 differ
diff --git a/documentation/docs/public/fonts/JetBrainsMono-Regular.woff2 b/documentation/docs/public/fonts/JetBrainsMono-Regular.woff2
new file mode 100644
index 0000000000..40da427651
Binary files /dev/null and b/documentation/docs/public/fonts/JetBrainsMono-Regular.woff2 differ
diff --git a/documentation/docs/public/fonts/JetBrainsMono-SemiBold.woff2 b/documentation/docs/public/fonts/JetBrainsMono-SemiBold.woff2
new file mode 100644
index 0000000000..5ead7b0d6f
Binary files /dev/null and b/documentation/docs/public/fonts/JetBrainsMono-SemiBold.woff2 differ
diff --git a/documentation/docs/theme.config.tsx b/documentation/docs/theme.config.tsx
index 8906294882..c223e68178 100644
--- a/documentation/docs/theme.config.tsx
+++ b/documentation/docs/theme.config.tsx
@@ -139,7 +139,7 @@ const config: DocsThemeConfig = {
>
);
},
- logo: Nym Docs ,
+ logo: Nym Docs ,
project: {
link: "https://github.com/nymtech/nym",
},
diff --git a/lychee.toml b/lychee.toml
index 42ea21812d..7dff1a851a 100644
--- a/lychee.toml
+++ b/lychee.toml
@@ -9,7 +9,7 @@ fallback_extensions = ["mdx", "md"]
# Remap /images to public/images for NextJS static assets
# Lychee resolves /images to pages/images, but Next.js serves from public/images
-remap = ["pages/images public/images"]
+remap = ["pages/images public/images", "pages/docs/fonts public/fonts"]
# Exclude component snippets (TODO: verify which are still in use)
exclude_path = ["components/"]