- Svelte 76.1%
- TypeScript 17.1%
- CSS 2.8%
- Python 2.2%
- HTML 1.1%
- Other 0.7%
Introduce a per-section "scene seam" so a deck can name a sceneId; when Nic later registers a .riv for it, premium devices render the Rive scene while potato/everyone keeps the SVG. The section-.riv registry map is EMPTY today, so every id resolves to null and the SVG always renders -- zero visual change. - RiveCanvas.svelte: bounded (non-fullscreen) Rive player extracted from RiveScene. Shares the self-hosted-wasm (?url + RuntimeLoader.setWasmUrl) and lifecycle pattern; dynamic-imports canvas-lite only on mount, sizes to its container (ResizeObserver), pauses on reduced-motion + hidden tab, and calls an onerror prop on load failure. - SceneFrame.svelte: the seam. Renders the SVG children by default; only swaps in RiveCanvas when sceneId is set, the device is premium (not potato, motion allowed), a .riv is registered, and it has mounted client-side. Reverts to the SVG on error. SSR emits the SVG; Rive is attempted only after hydration. - registry.ts: resolveSceneRiv(sceneId) backed by an empty map (returns null for all ids today) with a comment showing how to register one later. - StepDeck/ArgandDeck: optional sceneId prop wraps the scene render in SceneFrame. Threaded stable ids from all 7 callers (search-flow, principle, anti-ai, engine, supply-chain, why-gaps, argand-bio). - StepDeck optional autoplay (default OFF): auto-advance every ms, pause on hover + hidden tab, disabled under reduced motion. Not enabled on any caller yet. - Pure helpers shouldRenderRive() + autoplayActive() (plus a shared STEP_TRANSITION config) are unit-tested; registry test asserts every live sceneId resolves to null. Rive runtime stays a dynamic chunk via the canvas-lite dynamic import -- not in the main entry bundle. |
||
|---|---|---|
| .forgejo/workflows | ||
| content | ||
| docs | ||
| listmonk | ||
| scripts | ||
| src | ||
| static | ||
| .gitignore | ||
| .npmrc | ||
| energy-check.png | ||
| homepage-check.png | ||
| lighthouserc.json | ||
| package.json | ||
| pnpm-lock.yaml | ||
| presstrace-intro.png | ||
| principal-check.png | ||
| README.md | ||
| svelte.config.js | ||
| tsconfig.json | ||
| vite.config.ts | ||
| vitest.config.ts | ||
argand.org — pre-launch site
The public pre-launch site for Argand, an independent, privacy-first search engine built in pure Rust by one person. This repo is the marketing/landing site only; it is public on purpose, and is part of the project's trust story — so it is held to the same bar as the rest of Argand.
Live: https://argand.org
What's public here
- The full source of the landing site (SvelteKit +
adapter-static). - The deploy script (
scripts/deploy.sh). - The self-hosted double-opt-in email template (
listmonk/optin-welcome.html). - Trust artifacts:
security.txt, PGP key, and the genesis warrant canary (static/.well-known/).
What stays private until launch
- The search engine itself and its ~59 microservices / ~47 Rust crates.
- The crawl, index, ranking models, and the Argand Plane vector store.
- The
/api/newsletter-subscribeendpoint implementation (a same-origin proxy to a self-hosted Listmonk instance on Argand's own infrastructure).
Stack
- SvelteKit 2 (Svelte 5 runes) + TypeScript,
@sveltejs/adapter-static(fully prerendered — no server at runtime). - A strict Content-Security-Policy, self-hosted fonts/images, no third-party scripts.
vitestfor unit tests.
Develop
pnpm install
pnpm dev # local dev server
pnpm check # svelte-check / type check
pnpm test # vitest
pnpm build # prerender to ./build
pnpm preview # preview the production build
Node 22+, pnpm 10+.
Project structure
src/
routes/ # one folder per page (all prerendered)
+layout.svelte # site nav, footer, global <head>, JSON-LD
+page.svelte # short, conversion-focused homepage
benchmarks/ privacy/ presstrace/ roadmap/ about/ updates/
security-policy/ accessibility/ press/
sitemap.xml/+server.ts # generated at build time
feed.xml/+server.ts # generated at build time
lib/
components/ # SeoHead, OnThisPage, PageHeader, sections/, decks
data/ # services + updates (build log) data
nav/site.ts # routes, nav links, absolute-url helper
seo/ # pure sitemap + feed builders (unit-tested)
static/
fonts/ images/ icons/ # self-hosted assets
robots.txt opensearch.xml site.webmanifest
.well-known/ # security.txt, pgp key, warrant canary
The waitlist flow
Both signup forms (newsletter + early-accounts) are progressively enhanced:
they are real <form method="POST" action="/api/newsletter-subscribe"> elements
with native HTML validation, and JavaScript only layers on inline success/error
feedback. With JS disabled, the browser performs a normal POST and lands on a
real confirmation page.
How both paths complete (the /api/newsletter-subscribe endpoint is a
same-origin Caddy proxy to a self-hosted Listmonk; config outside this repo):
- JS path —
fetchposts JSON ({ email, list_uuids }). Caddy routesContent-Type: application/jsonto Listmonk's/api/public/subscription, which returns JSON; the component renders inline success/error. - No-JS path — the native form posts
application/x-www-form-urlencoded(email, plus a hiddenl= the list UUID, Listmonk's public-form param). Caddy routes urlencoded posts to Listmonk's/subscription/form, which subscribes and renders a real HTML confirmation page. Caddy also serves Listmonk's/subscription/*(confirm / unsubscribe / manage-prefs) and/public/static/*on-origin so those pages — and the unsubscribe links in emails (Listmonkroot_url=https://argand.org) — resolve under the brand domain. Admin (/admin, authed/api/*) is not proxied.
SEO & discovery
sitemap.xml,feed.xml: prerendered endpoints;<lastmod>/<lastBuildDate>are stamped from the build timestamp (vite.config.ts__BUILD_TIME__), so freshness never needs hand-editing.robots.txt: static; disallows/api/and points at the sitemap.- Structured data (JSON-LD): site-wide
Organization+WebSitein the layout<head>, plus a per-subpageBreadcrumbList(Home → page) emitted bySeoHeadfrom the route's nav label, all serialised through a<script>-safe helper (src/lib/seo/jsonld.ts). - Icons / PWA: regenerate with
uv run --with pillow --with fonttools --with brotli scripts/gen-icons.py(renders from the site's own Atkinson Hyperlegible woff2). opensearch.xmlis kept in the repo but intentionally not advertised via<link rel="search">until the engine is live.
Trust & policy
- Vulnerability disclosure:
/security-policy, machine-readable at/.well-known/security.txt. - Warrant canary:
/.well-known/canary.json(+ detached signature). Rotation ops are documented indocs/CANARY.md. - Privacy architecture:
/privacy. - Accessibility statement:
/accessibility.
Deploy
scripts/deploy.sh builds, packages, SHA-256-verifies the upload, extracts to a
timestamped release on the datalake, then atomically flips the current
symlink (keeping previous for rollback). Caddy serves current.
./scripts/deploy.sh
Quality / CI
CI (.forgejo/workflows/ci.yml) runs on every push: pnpm check, pnpm test,
pnpm build, plus an advisory Lighthouse pass. To run the Lighthouse audit
locally against a production build:
pnpm build
pnpm dlx @lhci/cli autorun # uses lighthouserc.json
Reporting issues
- Security: nic@argand.org (PGP welcome — see
/security-policy). - Accessibility: nic@argand.org — see
/accessibility. - Anything else: nic@argand.org.
License
Pre-launch. The site content and brand assets are © 2026 Nic Weyand, all rights reserved, unless noted otherwise.