Add DNS provider flow and demo site split

This commit is contained in:
jwinterm
2026-07-07 12:41:52 -04:00
parent 7f3631a624
commit 234a510798
13 changed files with 1729 additions and 20 deletions
+11 -6
View File
@@ -25,7 +25,7 @@
const topologies = {
vps: {
caption: "A VPS can publish clearnet, Tor, I2P, and Gemini outputs from one AMPG plan.",
caption: "A VPS can publish clearnet, Tor, I2P, Gemini, and Reticulum outputs from one AMPG plan.",
nodes: [
["source", "source site", 0.16, 0.42, "amber"],
["ampg", "AMPG", 0.34, 0.42, "teal"],
@@ -33,7 +33,8 @@
["web", "clearnet", 0.72, 0.22, "teal"],
["tor", "Tor", 0.78, 0.39, "coral"],
["i2p", "I2P", 0.76, 0.56, "amber"],
["gemini", "Gemini", 0.68, 0.72, "green"]
["gemini", "Gemini", 0.66, 0.72, "green"],
["reticulum", "Reticulum", 0.84, 0.72, "coral"]
],
links: [
["source", "ampg"],
@@ -41,11 +42,12 @@
["vps", "web"],
["vps", "tor"],
["vps", "i2p"],
["vps", "gemini"]
["vps", "gemini"],
["vps", "reticulum"]
]
},
router: {
caption: "Behind a router, clearnet may need DNS and port choices; Tor and I2P can avoid inbound port forwarding.",
caption: "Behind a router, clearnet may need DNS and port choices; Tor, I2P, and Reticulum can avoid depending on inbound web ports.",
nodes: [
["visitor", "visitor", 0.13, 0.33, "green"],
["dns", "DNS/DDNS", 0.3, 0.24, "amber"],
@@ -53,7 +55,8 @@
["host", "home host", 0.61, 0.38, "teal"],
["ampg", "AMPG", 0.76, 0.38, "teal"],
["tor", "Tor", 0.64, 0.66, "coral"],
["i2p", "I2P", 0.82, 0.66, "amber"]
["i2p", "I2P", 0.78, 0.66, "amber"],
["reticulum", "Reticulum", 0.9, 0.54, "green"]
],
links: [
["visitor", "dns"],
@@ -62,8 +65,10 @@
["host", "ampg"],
["ampg", "tor"],
["ampg", "i2p"],
["ampg", "reticulum"],
["visitor", "tor"],
["visitor", "i2p"]
["visitor", "i2p"],
["visitor", "reticulum"]
]
},
phone: {
+65 -3
View File
@@ -19,6 +19,7 @@
<span>AMPGateway</span>
</a>
<nav class="top-nav" aria-label="Primary">
<a href="#transport-flows">Transports</a>
<a href="#topologies">Topologies</a>
<a href="#domains">Domains</a>
<a href="#flow">Flow</a>
@@ -42,7 +43,7 @@
without losing the map.
</p>
<div class="hero-actions" aria-label="Primary sections">
<a class="button primary" href="#topologies">Explore topologies</a>
<a class="button primary" href="#transport-flows">Explore transports</a>
<a class="button secondary" href="#domains">See example domains</a>
</div>
</div>
@@ -55,11 +56,72 @@
<button class="mode-button" type="button" data-topology="browser">Browser</button>
</div>
<p id="topologyCaption" class="topology-caption" aria-live="polite">
A VPS can publish clearnet, Tor, I2P, and Gemini outputs from one AMPG plan.
A VPS can publish clearnet, Tor, I2P, Gemini, and Reticulum outputs from one AMPG plan.
</p>
</div>
</section>
<section id="transport-flows" class="section transport-section" aria-labelledby="transport-flows-title">
<div class="section-heading">
<p class="eyebrow">Traffic flows</p>
<h2 id="transport-flows-title">Same source, different paths through the network.</h2>
<p>
AMPG keeps the authoring path consistent while each transport uses the shape
that fits its network, daemon, and client expectations.
</p>
</div>
<div class="transport-flow-grid">
<article class="transport-flow">
<h3>Clearnet</h3>
<ol>
<li>Visitor resolves DNS for the site domain.</li>
<li>HTTP or HTTPS reaches the public web server.</li>
<li>The server reads AMPG clearnet output.</li>
</ol>
</article>
<article class="transport-flow">
<h3>Tor onion</h3>
<ol>
<li>Tor client resolves the onion service descriptor.</li>
<li>Tor circuits connect to the hidden service.</li>
<li>The local service serves AMPG privacy HTML.</li>
</ol>
</article>
<article class="transport-flow">
<h3>I2P tunnel</h3>
<ol>
<li>I2P client resolves the b32 destination.</li>
<li>Inbound and outbound tunnels carry HTTP.</li>
<li>i2pd forwards to the local AMPG output.</li>
</ol>
</article>
<article class="transport-flow">
<h3>Gemini</h3>
<ol>
<li>Client opens a TLS connection to the capsule.</li>
<li>Gemini server maps the URL to Gemtext.</li>
<li>The rendered page keeps links and headings simple.</li>
</ol>
</article>
<article class="transport-flow">
<h3>Reticulum</h3>
<ol>
<li>Client reaches an RNS destination.</li>
<li>NomadNet-style pages request compact Micron content.</li>
<li>AMPG output keeps media and layout intentionally small.</li>
</ol>
</article>
<article class="transport-flow">
<h3>Single transport</h3>
<ol>
<li>Operator enables only the target protocol.</li>
<li>AMPG builds only the selected output.</li>
<li>Deploy stages skip unrelated daemons and DNS.</li>
</ol>
</article>
</div>
</section>
<section id="topologies" class="section split" aria-labelledby="topologies-title">
<div>
<p class="eyebrow">Network topologies</p>
@@ -70,7 +132,7 @@
<h3>Full VPS</h3>
<p>
<code>ampgateway.site</code> is the target for a full public example with
clearnet, Tor, I2P, and Gemini routes managed from one deploy plan.
clearnet, Tor, I2P, Gemini, and Reticulum routes managed from one deploy plan.
</p>
</article>
<article>
+30 -5
View File
@@ -298,14 +298,16 @@ h3 {
}
.topology-grid,
.domain-grid {
.domain-grid,
.transport-flow-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 14px;
}
.topology-grid article,
.domain-card {
.domain-card,
.transport-flow {
min-height: 190px;
padding: 20px;
border: 1px solid var(--line);
@@ -314,14 +316,17 @@ h3 {
}
.topology-grid article:nth-child(2),
.domain-card.featured {
.domain-card.featured,
.transport-flow:nth-child(2n) {
background: var(--panel-strong);
}
.topology-grid p,
.domain-card p,
.docs-section p,
.flow-list p {
.flow-list p,
.transport-flow li,
.section-heading p {
color: var(--muted);
}
@@ -329,6 +334,25 @@ h3 {
margin-bottom: 28px;
}
.transport-flow-grid {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.transport-flow {
min-height: 250px;
}
.transport-flow h3 {
font-size: 1.35rem;
}
.transport-flow ol {
display: grid;
gap: 10px;
margin: 16px 0 0;
padding-left: 20px;
}
.domain-grid {
grid-template-columns: 1.2fr 1fr 1fr;
}
@@ -454,7 +478,8 @@ h3 {
}
.domain-grid,
.topology-grid {
.topology-grid,
.transport-flow-grid {
grid-template-columns: 1fr;
}
+41
View File
@@ -0,0 +1,41 @@
(function () {
const filters = Array.from(document.querySelectorAll("[data-filter]"));
const products = Array.from(document.querySelectorAll("[data-category]"));
const estimate = document.getElementById("estimate");
if (filters.length === 0 || products.length === 0) {
return;
}
function setFilter(category) {
filters.forEach((button) => {
const selected = button.dataset.filter === category;
button.classList.toggle("active", selected);
button.setAttribute("aria-pressed", selected ? "true" : "false");
});
let total = 0;
let count = 0;
products.forEach((product) => {
const visible = category === "all" || product.dataset.category === category;
product.hidden = !visible;
if (visible) {
count += 1;
total += Number(product.dataset.price || 0);
}
});
if (estimate) {
estimate.textContent =
count === products.length
? `All ${count} kits total $${total}.`
: `${count} matching kits total $${total}.`;
}
}
filters.forEach((button) => {
button.addEventListener("click", () => setFilter(button.dataset.filter || "all"));
});
setFilter("all");
})();
+169
View File
@@ -0,0 +1,169 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Field Kit Supply</title>
<meta
name="description"
content="AMPGateway demo site showing a small catalog, contact form, and transport-aware static fallbacks."
>
<link rel="stylesheet" href="styles.css">
<script defer src="app.js"></script>
</head>
<body>
<a class="skip-link" href="#content">Skip to content</a>
<header class="site-header">
<a class="brand" href="#content" aria-label="Field Kit Supply home">
<span class="brand-mark" aria-hidden="true">F</span>
<span>Field Kit Supply</span>
</a>
<nav class="top-nav" aria-label="Primary">
<a href="#catalog">Catalog</a>
<a href="#order">Order</a>
<a href="#transport-notes">Transport Notes</a>
</nav>
</header>
<!--
AMPG demo note:
The page starts with ordinary h1 -> h2 -> h3 structure and useful paragraphs.
Clearnet can enhance this with CSS and JavaScript, while Tor/I2P privacy HTML,
Gemini Gemtext, and Reticulum Micron still get a readable catalog.
-->
<main id="content">
<section class="hero" aria-labelledby="hero-title">
<div>
<p class="eyebrow">Demo shop</p>
<h1 id="hero-title">Small gear, published everywhere.</h1>
<p>
This is a fictional static storefront used to test AMPGateway outputs across
clearnet, Tor, I2P, Gemini, and Reticulum.
</p>
<a class="button" href="#catalog">Browse kits</a>
</div>
<aside class="status-board" aria-labelledby="status-title">
<h2 id="status-title">Transport behavior</h2>
<ul>
<li><strong>Clearnet:</strong> enhanced filters and order estimate.</li>
<li><strong>Tor/I2P:</strong> local assets, no scripts, same readable form.</li>
<li><strong>Gemini:</strong> catalog and links become Gemtext.</li>
<li><strong>Reticulum:</strong> compact Micron page for NomadNet-style reading.</li>
</ul>
</aside>
</section>
<section id="catalog" class="section" aria-labelledby="catalog-title">
<div class="section-heading">
<p class="eyebrow">Catalog</p>
<h2 id="catalog-title">Static inventory with optional enhancement.</h2>
<p>
The cards are plain HTML articles. JavaScript adds filtering on clearnet; the
rendered privacy and text outputs keep the same source order.
</p>
</div>
<div class="filters" aria-label="Catalog filters">
<button class="filter active" type="button" data-filter="all">All</button>
<button class="filter" type="button" data-filter="field">Field</button>
<button class="filter" type="button" data-filter="power">Power</button>
<button class="filter" type="button" data-filter="signals">Signals</button>
</div>
<div class="catalog-grid">
<article class="product" data-category="field" data-price="24">
<p class="tag">Field</p>
<h3>Pocket repair roll</h3>
<p>Compact thread, cord, patches, clips, and a tiny notebook for field fixes.</p>
<p class="price">$24</p>
</article>
<article class="product" data-category="power" data-price="38">
<p class="tag">Power</p>
<h3>Low-draw light kit</h3>
<p>Warm LEDs, diffuser caps, and a short cable set for off-grid worktables.</p>
<p class="price">$38</p>
</article>
<article class="product" data-category="signals" data-price="31">
<p class="tag">Signals</p>
<h3>Marker stack</h3>
<p>Weatherproof tags, reflective strips, and write-on tabs for route labeling.</p>
<p class="price">$31</p>
</article>
<article class="product" data-category="field" data-price="19">
<p class="tag">Field</p>
<h3>Dry pocket ledger</h3>
<p>Small waterproof pages for notes, receipts, map points, and handoff lists.</p>
<p class="price">$19</p>
</article>
</div>
</section>
<!--
AMPG demo note:
The form action is deliberately a normal HTTP path, not a JavaScript-only
checkout. Future AMPG app adapters can map this route to sessions or payments,
while static-only transports can still publish the request shape.
-->
<section id="order" class="section order-section" aria-labelledby="order-title">
<div>
<p class="eyebrow">Order request</p>
<h2 id="order-title">A boring form is a portable interface.</h2>
<p>
This demo does not submit real payments. It models the shape AMPG should
support later: static catalog, optional identity, optional payment, and a
server action only where the selected transport can safely handle it.
</p>
</div>
<form class="order-form" method="post" action="/orders/request">
<label>
Contact
<input name="contact" type="text" autocomplete="email" placeholder="name@example.test">
</label>
<label>
Kit
<select name="kit">
<option>Pocket repair roll</option>
<option>Low-draw light kit</option>
<option>Marker stack</option>
<option>Dry pocket ledger</option>
</select>
</label>
<label>
Notes
<textarea name="notes" rows="4" placeholder="Transport, delivery, or payment notes"></textarea>
</label>
<button type="submit">Request order</button>
<p id="estimate" class="estimate" aria-live="polite">Select catalog items to estimate a bundle.</p>
</form>
</section>
<section id="transport-notes" class="section notes-section" aria-labelledby="notes-title">
<p class="eyebrow">Cookbook</p>
<h2 id="notes-title">What this demo is proving.</h2>
<div class="notes-grid">
<article>
<h3>Keep content first</h3>
<p>Use headings, paragraphs, lists, and forms before decorative layout.</p>
</article>
<article>
<h3>Enhance gently</h3>
<p>JavaScript may improve clearnet, but the source page must remain useful without it.</p>
</article>
<article>
<h3>Declare route intent</h3>
<p>Static routes can publish everywhere; sessions and payments need transport policy.</p>
</article>
<article>
<h3>Publish fixtures</h3>
<p>Every transport output should have a health-checkable public URL.</p>
</article>
</div>
</section>
</main>
<footer class="site-footer">
<p>Fictional demo content for AMPGateway.</p>
<a href="https://ampgateway.online">System guide</a>
</footer>
</body>
</html>
+370
View File
@@ -0,0 +1,370 @@
:root {
color-scheme: light;
--paper: #f7f4ec;
--ink: #151615;
--muted: #60645f;
--line: #d8d0c0;
--panel: #fffdf7;
--field: #2f8f83;
--power: #b24f38;
--signal: #445fb0;
--gold: #c48a24;
--max: 1120px;
}
* {
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
margin: 0;
background:
linear-gradient(rgba(21, 22, 21, 0.035) 1px, transparent 1px),
linear-gradient(90deg, rgba(21, 22, 21, 0.03) 1px, transparent 1px),
var(--paper);
background-size: 32px 32px;
color: var(--ink);
font-family:
ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
sans-serif;
line-height: 1.55;
}
a {
color: inherit;
}
.skip-link {
position: fixed;
top: 12px;
left: 12px;
z-index: 20;
padding: 8px 10px;
background: var(--ink);
color: var(--paper);
transform: translateY(-140%);
}
.skip-link:focus {
transform: translateY(0);
}
.site-header {
position: sticky;
top: 0;
z-index: 10;
display: flex;
align-items: center;
justify-content: space-between;
gap: 20px;
padding: 14px clamp(18px, 4vw, 46px);
background: rgba(247, 244, 236, 0.9);
border-bottom: 1px solid var(--line);
backdrop-filter: blur(14px);
}
.brand,
.top-nav {
display: flex;
align-items: center;
}
.brand {
gap: 10px;
font-weight: 900;
text-decoration: none;
}
.brand-mark {
display: inline-grid;
width: 26px;
height: 26px;
place-items: center;
background: var(--field);
color: white;
font-weight: 900;
}
.top-nav {
gap: clamp(10px, 2vw, 22px);
color: var(--muted);
font-size: 0.94rem;
}
.top-nav a {
text-decoration: none;
}
.top-nav a:hover,
.top-nav a:focus-visible {
color: var(--ink);
}
.hero,
.section {
width: min(var(--max), calc(100% - 36px));
margin: 0 auto;
}
.hero {
display: grid;
grid-template-columns: minmax(0, 1.2fr) minmax(320px, 0.8fr);
gap: clamp(28px, 5vw, 64px);
align-items: end;
min-height: 74vh;
padding: clamp(70px, 12vw, 140px) 0 clamp(52px, 8vw, 92px);
}
.eyebrow,
.tag {
margin: 0 0 10px;
color: var(--gold);
font-size: 0.76rem;
font-weight: 900;
letter-spacing: 0.12em;
text-transform: uppercase;
}
h1,
h2,
h3,
p {
margin-top: 0;
}
h1 {
max-width: 760px;
margin-bottom: 18px;
font-size: clamp(3.2rem, 8vw, 7rem);
line-height: 0.94;
letter-spacing: 0;
}
h2 {
max-width: 720px;
margin-bottom: 16px;
font-size: clamp(1.8rem, 3.4vw, 3.8rem);
line-height: 1.04;
letter-spacing: 0;
}
h3 {
margin-bottom: 10px;
font-size: 1.15rem;
letter-spacing: 0;
}
.hero p,
.section-heading p,
.order-section p,
.notes-grid p,
.status-board li,
.product p {
color: var(--muted);
}
.button,
.order-form button,
.filter {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 44px;
border: 1px solid var(--ink);
border-radius: 6px;
font: inherit;
font-weight: 900;
text-decoration: none;
}
.button,
.order-form button {
margin-top: 16px;
padding: 10px 16px;
background: var(--ink);
color: var(--paper);
}
.status-board,
.product,
.order-form,
.notes-grid article {
border: 1px solid var(--line);
border-radius: 8px;
background: var(--panel);
}
.status-board {
padding: 22px;
}
.status-board h2 {
font-size: 1.2rem;
}
.status-board ul {
display: grid;
gap: 10px;
margin: 0;
padding-left: 18px;
}
.section {
padding: clamp(58px, 9vw, 104px) 0;
border-top: 1px solid var(--line);
}
.section-heading {
max-width: 720px;
margin-bottom: 26px;
}
.filters {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 16px;
}
.filter {
padding: 8px 14px;
background: transparent;
color: var(--ink);
cursor: pointer;
}
.filter.active,
.filter:focus-visible {
background: var(--signal);
color: white;
border-color: var(--signal);
}
.catalog-grid,
.notes-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 14px;
}
.product,
.notes-grid article {
padding: 20px;
}
.product {
display: flex;
min-height: 230px;
flex-direction: column;
}
.product[hidden] {
display: none;
}
.price {
margin-top: auto;
color: var(--power) !important;
font-size: 1.8rem;
font-weight: 900;
}
.order-section {
display: grid;
grid-template-columns: minmax(0, 0.9fr) minmax(320px, 0.7fr);
gap: clamp(28px, 6vw, 72px);
align-items: start;
}
.order-form {
display: grid;
gap: 14px;
padding: 20px;
}
.order-form label {
display: grid;
gap: 6px;
color: var(--muted);
font-size: 0.92rem;
font-weight: 800;
}
.order-form input,
.order-form select,
.order-form textarea {
width: 100%;
border: 1px solid var(--line);
border-radius: 6px;
background: white;
color: var(--ink);
font: inherit;
padding: 10px 12px;
}
.estimate {
min-height: 24px;
margin: 0;
color: var(--field) !important;
font-weight: 800;
}
.site-footer {
display: flex;
justify-content: space-between;
gap: 20px;
padding: 28px clamp(18px, 4vw, 46px);
border-top: 1px solid var(--line);
color: var(--muted);
}
.site-footer p {
margin: 0;
}
.site-footer a {
color: var(--signal);
font-weight: 900;
text-decoration: none;
}
@media (max-width: 900px) {
.top-nav {
display: none;
}
.hero,
.order-section {
grid-template-columns: 1fr;
}
.catalog-grid,
.notes-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 620px) {
h1 {
font-size: clamp(2.9rem, 17vw, 4.5rem);
}
.catalog-grid,
.notes-grid {
grid-template-columns: 1fr;
}
.button,
.filter,
.order-form button {
width: 100%;
}
.site-footer {
display: grid;
}
}