Marketing and documentation site for White Noise, built with SvelteKit.
Agent-readable responses, discovery formats, deployment checks and the applicability of service-specific recommendations are documented in Agent access.
Use Node 22 and Bun 1.4.2, matching CI and the Vercel runtime.
bun install --frozen-lockfile
bun run devDevelopment and production preview servers listen on the local network for phone testing. Open the Network URL printed by Vite on a phone connected to the same Wi-Fi. Keep the server running during review and use the default scripts rather than overriding the host with 127.0.0.1.
bun run test
bun run lint:write
bun run format
bun run check
bun run build- Navigation destinations and active-page rules live in
src/lib/navigation.ts, with guide paths and sections insrc/lib/documentation-navigation.ts. The header and closing Download section live insrc/lib/components/siteand are rendered once by the root layout. Shared UI primitives live insrc/lib/components/system. - Appearance follows the device by default, with a persistent light/dark icon toggle in the top navigation. The small
static/theme.jsbootstrap applies saved choices before page paint; the design-system catalog owns both palettes. src/lib/design-system/README.mddocuments the active tokens, typography and component contracts./design-systemis the noindex reference, omitted from navigation and the sitemap. Runbun run tokens:generateafter editing a catalog and include its generated CSS and runtime constants with the source.- Homepage features live in
src/lib/content/homepage.ts; FAQ pages, structured data and text exports sharesrc/lib/content/faqs.ts. The short Agents, Build and Marmot guides use local Markdown insrc/lib/content; full upstream documentation remains on GitHub. Legacy documentation URLs retain their redirects. - Blog posts and canary attestations come from Nostr. Keep their loaders, sanitization, cache behavior and signed data intact. The privacy policy source is
src/lib/content/privacy-policy.md. - Generated exports and temporary browser evidence belong in ignored
output/ortmp/directories. They are not production assets. Superseded design explorations and screenshots remain recoverable from Git history. - The site uses the Vercel adapter.
bun run ciruns the release checks locally; publishing still requires explicit authorization.
Marketing pages, the FAQ, and the Agents, Build and Marmot guides are pre-rendered. The shared docs route uses an explicit Marmot README entry with prerender = "auto"; other documentation URLs remain server redirects and do not initialize the guide renderer. The legacy .md page URL serves HTML by default through file-specific Build Output MIME metadata, and serves Markdown when explicitly requested; the preview middleware maps it to the generated .html file because SvelteKit preview otherwise infers Markdown MIME from the URL. Blog content, canary attestations and the sitemap also use server routes. No relay access is needed to build static pages. The page shell includes a styled error route; content outages return 503 rather than a misleading 404.
Relay transport lives under src/lib/server. It verifies signatures, author, kind and filters, chooses the newest replaceable event, and closes requests within ten seconds. Requests retain verified partial results. List and article caches coalesce concurrent reads, expire after five minutes, and allow at most one hour of stale blog content after refresh failures. Expired missing-post results are never served as stale content during an outage. Caches are process-local and bounded; they are not persistent storage. Canary data is cached for one minute with no stale-on-error fallback. The page renders the signed statement verbatim, escaped as text.
The content security policy permits same-origin code and the existing analytics.ipf.dev service. Inline style attributes remain allowed for measured artwork and the live design reference; inline executable scripts require SvelteKit's generated hashes/nonces. Blog images may use HTTP(S) origins. Framing is denied, content sniffing is disabled, and cross-origin referrers are limited. Vercel applies the static-asset headers as well. Keep deployment policy in sync with the local server hooks.
/llms.txt and /llms-full.txt retain their public URLs and are generated from the overview, FAQ and guide sources. They no longer claim to contain full upstream documentation. The sitemap reports article modification dates and does not invent fresh modification dates for static pages.
Agent setup prompts live in agent-setup fences in src/lib/content/agents.md; the guide's visible prompt containers, copy controls and text export share this source. Guide Markdown is rendered once per server instance; page data contains either one article or sections with prompts, without a duplicate full article. Keep the runtime-specific prerequisites and installation-approval step when updating them.
The cookie dependency override applies the upstream 0.7.x validation fix for GHSA-pxg6-pf52-xh8x while SvelteKit declares the older range. Recheck this override when updating SvelteKit; remove it once the framework resolves a fixed version itself.
The devalue override applies the compatible 5.x fixes for shared-buffer serialization and related 5.9.2 advisories; source-map-js applies the 1.2.2 source-map denial-of-service fix. Both were required by the dependency audit before agent-access validation could run. Recheck and remove these overrides when upstream dependencies resolve patched versions without them.
Existing /images/rebuild/ paths are stable public asset URLs retained for compatibility. Site components and styles use durable site naming. The design system's documentation catalog is isolated from normal page runtime imports; small generated constants supply breakpoint and copy-feedback behavior.
Public availability copy describes the intended launch state, when both iPhone and Android apps are available. The App Store and Google Play buttons are user-approved active placeholders: clicking stays on the Download page. They are excluded from structured download URLs. Zapstore and the direct APK retain their real destinations. Replace the placeholders only when store URLs are supplied.
Manrope is self-hosted through @fontsource-variable/manrope. The canonical WN mark, supporter logos, social preview and application icons remain in static/.
The IPF supporter lettermark was adapted from the official IPF favicon on September 15, 2026: its straight-edged letter contours were traced into SVG, the square background removed, and the letters made black as requested. Its optical frame and the OpenSats frame are documented in the design-system README; original letter shapes and proportions are preserved.
Current illustrations in static/images/artwork/ are the user-approved WebPs from /Users/vladimirkrstic/Workspaces/ffmpeg-tools/output/half-size-webp-2026-09-13, supplied September 13, 2026. Copy these files unchanged; do not re-encode them. Source dimensions and visible alpha bounds (above 16, excluding near-transparent export noise) live in src/lib/design-system/artwork.ts. The shared viewport preserves proportions and uses the approved artwork layout.
| Site asset | Supplied file | Placement |
|---|---|---|
conversation.webp |
Private Conversation-half.webp |
Private messages. Private groups. |
identity-balloon.webp |
Woman With A Balloon-half.webp |
No phone number. No email. |
agent-contact.webp |
Agent-half.webp |
All your AI in a single app |
network-flower.webp |
Girl With A Flower-half.webp |
No central server. No lock-in. |
band.webp |
Band-half.webp |
We can’t lock you in. |
children-plant.webp |
Children Holding Plant-half.webp |
Open source. Open standards.; Contribute introduction |
smith-chain.webp |
Smith & Chain-half.webp |
Built with the community.; Download feedback section |
The seven distinct active illustrations total 1.97 MB. Explorer Boy-half.webp is not used in the selected composition. Earlier /images/rebuild/ URLs remain available for compatibility. Original Figma exports came from the Marketing file: lantern 25:18, roots 112:2, identity 25:187, community 120:17, agents 25:303, open 35:21.
The website copy is editable, but security and availability claims need source verification. Consult the Marmot protocol, MLS standard, native iOS and Android clients, and agent integration documentation. Platform statements must agree with the current Download destinations; privacy disclosures must agree with the policy.
Do not equate identity-key reuse with synchronized message history, claim guaranteed anonymity or connectivity, or imply that encrypted agent transport makes a cloud model run locally. Preserve donation addresses, payment URIs and download destinations unless an update is explicitly approved.
Responsive release review should cover desktop, tablet, 320px, keyboard navigation and actual browser 200% zoom. A narrower viewport alone is not proof of a completed browser-zoom check.
The security contact in static/.well-known/security.txt uses the published IPF security address, replacing the archived app repository. Confirm that mailbox ownership remains current during release review.
The /canary page fetches signed White Noise canary attestations from Nostr.
Current setup:
- custom immutable event kind:
303 - author pubkey:
75d737c3472471029c44876b330d2284288a42779b591a2ed4daa1c6c07efaf7 - relays:
wss://relay.primal.netwss://nos.lolwss://relay.ditto.pubwss://relay.eu.whitenoise.chatwss://relay.us.whitenoise.chatwss://relay.jeffg.fyi
Recommended event shape for published canary events:
kind: 303content: the human-readable canary statement- tags:
titlet=canaryt=attestationr=https://www.whitenoise.chat/canary- one
relaystag containing all publication relays
Example tag set:
["title", "White Noise Canary — March 30, 2026"]
["t", "canary"]
["t", "attestation"]
["r", "https://www.whitenoise.chat/canary"]
["relays", "wss://relay.primal.net", "wss://nos.lol", "wss://relay.ditto.pub", "wss://relay.eu.whitenoise.chat", "wss://relay.us.whitenoise.chat", "wss://relay.jeffg.fyi"]
Use the helper script in this repo:
NOSTR_SECRET_KEY=<white-noise-nsec> bun run canary:publishYou can optionally override the generated title:
NOSTR_SECRET_KEY=<white-noise-nsec> bun run canary:publish -- "White Noise Canary — March 2026"The script generates the standard canary text automatically using the current date, publishes a kind 303 event to all configured relays, adds a single relays tag listing those relays, and includes the canonical /canary page in the r tag.
To publish one or more events with historical dates, repeat --date. Historical events use noon UTC on the specified date for created_at. The script displays the dates and asks for confirmation before signing and publishing them:
NOSTR_SECRET_KEY=<white-noise-nsec> bun run canary:publish -- \
--date 2026-04-30 \
--date 2026-05-31 \
--date 2026-06-30 \
--date 2026-07-31Pass --yes to skip the batch confirmation in an already-approved, non-interactive run. Before publishing, the script verifies that NOSTR_SECRET_KEY belongs to the White Noise pubkey. The secret is read from the environment and is not passed in the nak process arguments.
To inspect the exact unsigned event JSON before signing or publishing:
./scripts/publish-canary.sh --dry-runYou can also provide a custom title:
./scripts/publish-canary.sh --dry-run "White Noise Canary — March 2026"Dry-run historical events by repeating --date:
./scripts/publish-canary.sh --dry-run \
--date 2026-04-30 \
--date 2026-05-31This prints the event through jq, including:
kindcontent- the full
tagsarray
- App Store and Google Play URLs have not been supplied. The Download page keeps the user-approved active placeholders described above; Zapstore and the APK have real destinations.
- The pale hero gray is an accepted exception to large-text AA contrast, recorded in the design system.
- “Holding Ourselves to It” on Privacy Matters contains absolute privacy/anonymization claims that conflict with the policy's stated limitations. That copy still needs a separate content review; the canonical policy is unchanged.
- Vercel's build tracer reports the optional
supports-colordependency ofdebug. Local production builds and tested routes work without it.
Before publishing, verify deployed headers and domain redirects, check mobile Safari on a physical device, and resolve the outstanding content and store-destination decisions. Keep dated test results and browser evidence in ignored tmp/ or output/, rather than maintaining a second release log here.
Favicon artwork uses the exact path from static/images/logomark.svg, centered without distortion in a square: white on ink for light mode, ink on white for dark mode. favicon.svg follows device appearance without JavaScript; the theme controller selects explicit SVG, PNG and ICO variants when running. SVG is preferred, with a 96px PNG and multi-resolution 16/32/48/64/256px ICO fallback. The 180px Apple touch icon and 192/512px maskable manifest icons use the white-on-ink version; installed icons are not live theme controls. Maskable exports keep the complete mark inside the central 80% safe circle. Raster assets were rendered from these vector paths at 4× output resolution and downsampled, with independently rendered ICO entries. Regenerate them from the canonical path if the mark changes; never wrap raster data in SVG.