Files
nx9-www/www/case-study.html
T

1345 lines
75 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NX9 — Next Generation 9 | Software people can own, understand, and control</title>
<meta name="description" content="NX9 is a philosophy-driven ecosystem of self-hosted, privacy-first Rust software by Sunil Thakare. No telemetry. No vendor lock-in. Software people can own, understand, and control.">
<meta name="color-scheme" content="light dark">
<!-- Favicons & App Icons -->
<link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="192x192" href="/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/manifest.json">
<meta name="msapplication-TileColor" content="#020617">
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png">
<meta name="theme-color" content="#020617">
<style>
/* ============================================================
1. DESIGN TOKENS
============================================================ */
:root {
--bg: #ffffff;
--bg-raised: #ffffff;
--surface: #f5f6f9;
--surface-hover: #ecefF4;
--border: #e1e4ea;
--border-strong: #cbd0da;
--text: #12151a;
--text-secondary: #4b5563;
--text-muted: #6b7280;
--accent: #6d5df6;
--accent-strong: #5643e0;
--accent-soft: #eeecff;
--accent-contrast: #ffffff;
--dot: rgba(109, 93, 246, 0.14);
--line: rgba(109, 93, 246, 0.08);
--shadow: 0 1px 2px rgba(16, 20, 26, 0.04), 0 4px 16px rgba(16, 20, 26, 0.05);
--shadow-hover: 0 4px 10px rgba(109, 93, 246, 0.12), 0 16px 36px rgba(16, 20, 26, 0.1);
--radius: 10px;
--radius-sm: 6px;
--font-ui: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, sans-serif;
--font-mono: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
--content-max: 1180px;
--transition-theme: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease;
/* Gradient palette — reused across icons, borders and glow shadows */
--grad-1: linear-gradient(135deg, #7c5cf9, #b18bfa);
--grad-2: linear-gradient(135deg, #06b6d4, #5eead4);
--grad-3: linear-gradient(135deg, #f59e0b, #fb923c);
--grad-4: linear-gradient(135deg, #ec4899, #fb7185);
--grad-5: linear-gradient(135deg, #10b981, #6ee7b7);
--grad-6: linear-gradient(135deg, #3b82f6, #7dd3fc);
--grad-7: linear-gradient(135deg, #ef4444, #f97316);
--glow-1: rgba(124, 92, 249, .35);
--glow-2: rgba(6, 182, 212, .35);
--glow-3: rgba(245, 158, 11, .35);
--glow-4: rgba(236, 72, 153, .35);
--glow-5: rgba(16, 185, 129, .35);
--glow-6: rgba(59, 130, 246, .35);
--glow-7: rgba(239, 68, 68, .35);
}
html[data-theme="dark"] {
--bg: #0a0c10;
--bg-raised: #12151b;
--surface: #161a21;
--surface-hover: #1d222b;
--border: #262c37;
--border-strong: #363e4b;
--text: #eceef2;
--text-secondary: #a7aec0;
--text-muted: #7c8497;
--accent: #9d8bff;
--accent-strong: #b6a7ff;
--accent-soft: #1c1a33;
--accent-contrast: #0a0c10;
--dot: rgba(157, 139, 255, 0.16);
--line: rgba(157, 139, 255, 0.08);
--shadow: 0 1px 2px rgba(0, 0, 0, 0.35), 0 4px 20px rgba(0, 0, 0, 0.4);
--shadow-hover: 0 4px 14px rgba(157, 139, 255, 0.18), 0 18px 40px rgba(0, 0, 0, 0.45);
}
/* ============================================================
2. RESET & BASE
============================================================ */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
*, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; scroll-behavior: auto !important; }
}
body {
margin: 0;
font-family: var(--font-ui);
background-color: var(--bg);
color: var(--text);
line-height: 1.6;
transition: var(--transition-theme);
background-image:
linear-gradient(var(--line) 1px, transparent 1px),
linear-gradient(90deg, var(--line) 1px, transparent 1px),
radial-gradient(var(--dot) 1px, transparent 1px);
background-size: 64px 64px, 64px 64px, 16px 16px;
background-position: -1px -1px, -1px -1px, -1px -1px;
}
/* Logo Theme Dynamic Filter */
html[data-theme="light"] .nav-icon,
html[data-theme="light"] .hero-logo,
html[data-theme="light"] .footer-logo {
filter: invert(1) hue-rotate(180deg);
}
img { max-width: 100%; display: block; }
a { color: inherit; }
ul { list-style: none; margin: 0; padding: 0; }
h1, h2, h3, h4, p { margin: 0; }
button { font-family: inherit; }
table { border-collapse: collapse; width: 100%; }
::selection { background: var(--accent); color: var(--accent-contrast); }
a:focus-visible, button:focus-visible, summary:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 3px;
border-radius: var(--radius-sm);
}
.skip-link {
position: absolute; left: 1rem; top: -100px;
background: var(--accent); color: var(--accent-contrast);
padding: 0.65rem 1.1rem; border-radius: var(--radius-sm);
font-size: 0.9rem; font-weight: 600; z-index: 200;
transition: top 0.2s ease;
}
.skip-link:focus { top: 1rem; }
/* Hidden icon sprite sheet */
.icon-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.icon {
width: 20px; height: 20px;
stroke: currentColor;
fill: none;
stroke-width: 1.8;
stroke-linecap: round;
stroke-linejoin: round;
flex-shrink: 0;
}
.icon-badge {
width: 46px; height: 46px;
border-radius: var(--radius-sm);
display: flex; align-items: center; justify-content: center;
color: #fff;
margin-bottom: 1rem;
box-shadow: var(--shadow);
}
.icon-badge .icon { width: 24px; height: 24px; }
/* Gradient utility classes */
.grad-1 { background: var(--grad-1); }
.grad-2 { background: var(--grad-2); }
.grad-3 { background: var(--grad-3); }
.grad-4 { background: var(--grad-4); }
.grad-5 { background: var(--grad-5); }
.grad-6 { background: var(--grad-6); }
.grad-7 { background: var(--grad-7); }
/* ============================================================
3. LAYOUT PRIMITIVES
============================================================ */
.wrap { max-width: var(--content-max); margin-inline: auto; padding-inline: 1.5rem; }
section { padding-block: clamp(3.5rem, 7vw, 6.5rem); }
.section-head { max-width: 680px; margin-bottom: clamp(2rem, 4vw, 3rem); }
.eyebrow {
display: inline-flex; align-items: center; gap: 0.4rem;
font-family: var(--font-mono); font-size: 0.75rem;
letter-spacing: 0.14em; text-transform: uppercase;
background: linear-gradient(90deg, var(--accent), #ec4899);
-webkit-background-clip: text; background-clip: text; color: transparent;
margin-bottom: 0.75rem; font-weight: 700;
}
.section-title { font-size: clamp(1.6rem, 3.2vw, 2.25rem); font-weight: 800; letter-spacing: -0.01em; margin-bottom: 0.75rem; }
.section-sub { color: var(--text-secondary); font-size: 1.05rem; max-width: 65ch; }
/* ============================================================
4. NAVIGATION
============================================================ */
.site-header {
position: sticky; top: 0; z-index: 100;
background-color: color-mix(in srgb, var(--bg) 85%, transparent);
backdrop-filter: saturate(160%) blur(10px);
-webkit-backdrop-filter: saturate(160%) blur(10px);
border-bottom: 1px solid var(--border);
transition: var(--transition-theme);
}
.nav-inner {
max-width: var(--content-max); margin-inline: auto; padding: 0.85rem 1.5rem;
display: flex; align-items: center; justify-content: space-between; gap: 1rem;
}
.brand { display: flex; align-items: center; gap: 0.5rem; font-weight: 800; font-size: 1.15rem; letter-spacing: -0.01em; text-decoration: none; }
.nav-icon { height: 26px; width: auto; }
.nav-links { display: flex; align-items: center; gap: 0.15rem; }
.nav-links a {
text-decoration: none; font-size: 0.9rem; font-weight: 500; color: var(--text-secondary);
padding: 0.5rem 0.65rem; border-radius: var(--radius-sm);
transition: color 0.15s ease, background-color 0.15s ease;
}
.nav-links a:hover { color: var(--text); background-color: var(--surface); }
.nav-links a.is-active { color: var(--accent); }
.nav-right { display: flex; align-items: center; gap: 0.5rem; }
.theme-toggle {
display: inline-flex; align-items: center; gap: 0.4rem;
background: var(--surface); border: 1px solid var(--border); color: var(--text);
border-radius: var(--radius); padding: 0.45rem 0.7rem; font-size: 0.82rem;
font-family: var(--font-mono); cursor: pointer;
transition: background-color 0.15s ease, border-color 0.15s ease;
}
.theme-toggle:hover { background: var(--surface-hover); border-color: var(--border-strong); }
.hamburger {
display: none; background: transparent; border: 1px solid var(--border); border-radius: var(--radius-sm);
width: 40px; height: 40px; cursor: pointer; color: var(--text);
align-items: center; justify-content: center;
}
.hamburger span, .hamburger span::before, .hamburger span::after {
content: ""; display: block; width: 18px; height: 2px; background: currentColor; position: relative;
transition: transform 0.2s ease, opacity 0.2s ease;
}
.hamburger span::before { position: absolute; top: -6px; }
.hamburger span::after { position: absolute; top: 6px; }
.hamburger[aria-expanded="true"] span { background: transparent; }
.hamburger[aria-expanded="true"] span::before { transform: translateY(6px) rotate(45deg); }
.hamburger[aria-expanded="true"] span::after { transform: translateY(-6px) rotate(-45deg); }
@media (max-width: 860px) {
.hamburger { display: inline-flex; }
.nav-links {
position: fixed; inset: 61px 0 auto 0; flex-direction: column; align-items: stretch;
background: var(--bg-raised); border-bottom: 1px solid var(--border); padding: 0.5rem;
gap: 0; transform: translateY(-8px); opacity: 0; pointer-events: none;
transition: transform 0.18s ease, opacity 0.18s ease; max-height: 80vh; overflow-y: auto;
}
.nav-links.is-open { transform: translateY(0); opacity: 1; pointer-events: auto; }
.nav-links a { padding: 0.85rem 1rem; border-radius: var(--radius-sm); }
}
/* ============================================================
5. HERO
============================================================ */
.hero { padding-block: clamp(4rem, 10vw, 7.5rem) clamp(3rem, 6vw, 5rem); position: relative; overflow: hidden; }
.hero::before {
content: ""; position: absolute; top: -20%; right: -10%; width: 560px; height: 560px;
background: radial-gradient(circle, var(--glow-1), transparent 70%);
filter: blur(10px); pointer-events: none; opacity: 0.55; z-index: 0;
}
.hero::after {
content: ""; position: absolute; bottom: -30%; left: -10%; width: 480px; height: 480px;
background: radial-gradient(circle, var(--glow-2), transparent 70%);
filter: blur(10px); pointer-events: none; opacity: 0.4; z-index: 0;
}
.hero .wrap { position: relative; z-index: 1; }
.hero-kicker {
font-family: var(--font-mono); font-size: 0.8rem; letter-spacing: 0.16em; text-transform: uppercase;
color: var(--text-muted); margin-bottom: 1.25rem;
}
.hero-kicker::before { content: "$ "; color: var(--accent); }
.hero-logo { max-width: 600px; width: 100%; height: auto; margin-bottom: 1rem; filter: drop-shadow(0 20px 40px rgba(0,0,0,0.3)); }
.hero h2 { font-size: clamp(1.1rem, 2.6vw, 1.5rem); font-weight: 500; color: var(--text-secondary); margin-top: 0.6rem; letter-spacing: -0.005em; }
.hero blockquote {
margin: 1.75rem 0 1.5rem; padding-left: 1.1rem;
border-left: 3px solid transparent;
border-image: linear-gradient(180deg, var(--accent), #ec4899) 1;
font-size: clamp(1.05rem, 2vw, 1.3rem); font-weight: 600; max-width: 46ch;
}
.hero p.lede { max-width: 64ch; color: var(--text-secondary); font-size: 1.05rem; margin-bottom: 1.25rem; }
.hero-byline { font-size: 0.9rem; color: var(--text-muted); margin-bottom: 2rem; }
.hero-byline strong { color: var(--text-secondary); }
.hero-ctas { display: flex; flex-wrap: wrap; gap: 0.85rem; }
.btn {
position: relative; overflow: hidden; display: inline-flex; align-items: center; gap: 0.5rem;
font-weight: 600; font-size: 0.95rem; padding: 0.75rem 1.4rem; border-radius: var(--radius);
text-decoration: none; cursor: pointer; border: 1px solid transparent;
transition: transform 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
}
.btn:active { transform: translateY(1px); }
.btn-primary { background: linear-gradient(135deg, var(--accent), #ec4899); color: #fff; }
.btn-primary:hover { box-shadow: 0 10px 24px var(--glow-1); transform: translateY(-1px); }
.btn-outline { background: transparent; color: var(--text); border-color: var(--border-strong); }
.btn-outline:hover { background: var(--surface); border-color: var(--accent); }
.btn-sm { padding: 0.5rem 0.9rem; font-size: 0.85rem; }
.btn .ripple { position: absolute; border-radius: 50%; background: rgba(255,255,255,0.5); transform: scale(0); pointer-events: none; animation: ripple 0.6s ease-out; }
html[data-theme="dark"] .btn-outline .ripple { background: rgba(255,255,255,0.18); }
@keyframes ripple { to { transform: scale(3); opacity: 0; } }
/* ============================================================
6. ABOUT
============================================================ */
.about-panel {
background: linear-gradient(135deg, var(--accent-soft), var(--surface));
border: 1px solid var(--border); border-radius: var(--radius);
padding: clamp(1.5rem, 4vw, 2.5rem); font-size: 1.1rem; color: var(--text-secondary); line-height: 1.75;
}
.about-panel strong { color: var(--text); }
/* ============================================================
7. COLORFUL CARD GRIDS
============================================================ */
.card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(255px, 1fr)); gap: 1.15rem; }
.card {
background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius);
padding: 1.6rem; position: relative; overflow: hidden;
transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}
.card::before {
content: ""; position: absolute; top: 0; left: 0; right: 0; height: 4px;
background: var(--card-grad, var(--grad-1));
}
.card:hover { transform: translateY(-4px); box-shadow: 0 14px 34px var(--card-glow, var(--glow-1)); border-color: var(--border-strong); }
.card .icon-badge { background: var(--card-grad, var(--grad-1)); }
.card h3 { font-size: 1.08rem; font-weight: 700; margin-bottom: 0.5rem; }
.card p { color: var(--text-secondary); font-size: 0.94rem; }
.card ul { margin-top: 0.6rem; }
.card li {
color: var(--text-secondary); font-size: 0.9rem; position: relative; padding-left: 1.1rem; margin-top: 0.3rem;
}
.card li::before { content: "●"; position: absolute; left: 0; top: 0.05em; font-size: 0.55rem; color: var(--accent); }
.card .card-tag {
font-family: var(--font-mono); font-size: 0.68rem; letter-spacing: 0.04em; text-transform: uppercase;
color: var(--text-muted); display: block; margin-top: 0.9rem;
}
/* ============================================================
8. PROJECTS
============================================================ */
.callout {
display: flex; gap: 0.85rem; align-items: flex-start;
background: var(--accent-soft); border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--border));
border-radius: var(--radius); padding: 1.1rem 1.3rem; margin-bottom: 2rem; font-size: 0.95rem; color: var(--text-secondary);
}
.callout strong { color: var(--text); }
.callout .icon { color: var(--accent); margin-top: 0.15rem; }
.project-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.15rem; }
@media (max-width: 780px) { .project-grid { grid-template-columns: 1fr; } }
.project-card {
background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius);
padding: 1.6rem; display: flex; flex-direction: column; gap: 0.9rem; position: relative; overflow: hidden;
transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}
.project-card::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 4px; background: var(--card-grad, var(--grad-1)); }
.project-card:hover { transform: translateY(-4px); box-shadow: 0 14px 34px var(--card-glow, var(--glow-1)); border-color: var(--border-strong); }
.project-card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.75rem; }
.project-title { display: flex; align-items: center; gap: 0.65rem; }
.project-title .icon-badge { width: 38px; height: 38px; margin-bottom: 0; border-radius: var(--radius-sm); background: var(--card-grad, var(--grad-1)); }
.project-title .icon-badge .icon { width: 19px; height: 19px; }
.project-card h3 { font-family: var(--font-mono); font-size: 1.02rem; font-weight: 700; }
.status-badge {
font-family: var(--font-mono); font-size: 0.66rem; letter-spacing: 0.06em; text-transform: uppercase;
padding: 0.22rem 0.55rem; border-radius: 999px; white-space: nowrap; color: #fff; align-self: flex-start;
}
.project-card p.desc { color: var(--text-secondary); font-size: 0.93rem; }
.tech-badges { display: flex; flex-wrap: wrap; gap: 0.45rem; margin-top: 0.5rem; }
.tech-badge {
font-family: var(--font-mono); font-size: 0.72rem; color: #fff; border-radius: var(--radius-sm);
padding: 0.22rem 0.55rem; background: var(--card-grad, var(--grad-1)); opacity: 0.92;
}
.project-links { display: flex; gap: 0.6rem; margin-top: auto; padding-top: 0.5rem; }
/* ============================================================
9. STATS
============================================================ */
.stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1rem; text-align: center; }
.stat {
background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius);
padding: 1.75rem 1rem; position: relative; overflow: hidden;
}
.stat::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px; background: var(--card-grad, var(--grad-1)); }
.stat .num {
font-family: var(--font-mono); font-size: clamp(1.8rem, 4vw, 2.5rem); font-weight: 700; display: block;
background: var(--card-grad, var(--grad-1)); -webkit-background-clip: text; background-clip: text; color: transparent;
}
.stat .label { color: var(--text-secondary); font-size: 0.85rem; margin-top: 0.35rem; }
/* ============================================================
10. POSITIONING TABLE
============================================================ */
.positioning { overflow-x: auto; border-radius: var(--radius); border: 1px solid var(--border); }
.positioning table { min-width: 560px; }
.positioning th, .positioning td { text-align: left; padding: 0.9rem 1.2rem; font-size: 0.92rem; }
.positioning thead th {
font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.06em; text-transform: uppercase;
color: #fff; padding-block: 1rem;
}
.positioning thead th:first-child { background: var(--grad-7); }
.positioning thead th:last-child { background: var(--grad-5); }
.positioning tbody tr { border-top: 1px solid var(--border); background: var(--bg-raised); }
.positioning tbody tr:nth-child(even) { background: var(--surface); }
.positioning td:first-child { color: var(--text-muted); position: relative; padding-left: 2.2rem; }
.positioning td:first-child::before { content: "✕"; position: absolute; left: 1.2rem; color: #ef4444; font-weight: 700; font-size: 0.8rem; }
.positioning td:last-child { color: var(--text); font-weight: 600; position: relative; padding-left: 2.2rem; }
.positioning td:last-child::before { content: "✓"; position: absolute; left: 1.2rem; color: #10b981; font-weight: 700; font-size: 0.8rem; }
/* ============================================================
11. VISION
============================================================ */
.vision-panel {
position: relative; overflow: hidden;
background: linear-gradient(135deg, var(--accent-soft), var(--surface));
border: 1px solid var(--border); border-radius: var(--radius); padding: clamp(1.75rem, 5vw, 3rem);
}
.vision-panel::after {
content: ""; position: absolute; inset: 0; border-radius: var(--radius); padding: 1px;
background: linear-gradient(135deg, var(--accent), #ec4899, #06b6d4);
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
-webkit-mask-composite: xor; mask-composite: exclude; opacity: 0.5; pointer-events: none;
}
.vision-panel p {
font-size: clamp(1.1rem, 2.4vw, 1.4rem); font-weight: 500; letter-spacing: -0.005em; color: var(--text); max-width: 62ch; position: relative;
}
.vision-panel p + p { margin-top: 1.1rem; color: var(--text-secondary); font-weight: 400; font-size: clamp(1rem, 2vw, 1.15rem); }
/* ============================================================
12. VALUES
============================================================ */
.value-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(155px, 1fr)); gap: 0.8rem; }
.value-chip {
border: 1px solid var(--border); border-radius: var(--radius); padding: 1.2rem 0.9rem; text-align: center;
background: var(--bg-raised); position: relative; overflow: hidden;
transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}
.value-chip::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px; background: var(--card-grad, var(--grad-1)); }
.value-chip:hover { transform: translateY(-3px); box-shadow: 0 10px 24px var(--card-glow, var(--glow-1)); }
.value-chip .n {
font-family: var(--font-mono); font-size: 0.7rem; display: block; margin-bottom: 0.5rem; font-weight: 700;
background: var(--card-grad, var(--grad-1)); -webkit-background-clip: text; background-clip: text; color: transparent;
}
.value-chip .t { font-weight: 600; font-size: 0.95rem; }
/* ============================================================
13. ROADMAP
============================================================ */
.roadmap-intro { color: var(--text-secondary); max-width: 70ch; margin-bottom: 2.5rem; font-size: 1rem; }
.roadmap-intro strong { color: var(--text); }
.circuit { display: flex; align-items: flex-start; overflow-x: auto; padding-block: 1rem 0.5rem; scrollbar-width: thin; }
.node { flex: 1 0 100px; min-width: 100px; display: flex; flex-direction: column; align-items: center; text-align: center; position: relative; padding-top: 2.75rem; }
.node::before {
content: ""; position: absolute; top: 12px; left: -50%; width: 100%; height: 2px;
background: repeating-linear-gradient(90deg, var(--border-strong) 0 6px, transparent 6px 11px); z-index: 0;
}
.node:first-child::before { display: none; }
.node.is-active::before { background: repeating-linear-gradient(90deg, var(--accent) 0 6px, transparent 6px 11px); }
.node .pad {
width: 28px; height: 28px; border-radius: 50%; border: 2px solid var(--border-strong); background: var(--bg-raised);
display: flex; align-items: center; justify-content: center; font-family: var(--font-mono); font-size: 0.72rem;
font-weight: 700; color: var(--text-muted); position: absolute; top: 0; z-index: 1;
transition: transform 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
}
.node.is-active .pad {
border-color: transparent; background: var(--card-grad, var(--grad-1)); color: #fff;
box-shadow: 0 0 0 4px var(--card-glow, var(--glow-1));
}
.node:hover .pad { transform: scale(1.12); }
.node .name { font-family: var(--font-mono); font-size: 0.82rem; font-weight: 700; margin-top: 0.4rem; }
.node .state { font-size: 0.72rem; color: var(--text-muted); margin-top: 0.15rem; }
.node.is-active .state { color: var(--accent); font-weight: 600; }
@media (max-width: 720px) {
.circuit { flex-direction: column; align-items: stretch; overflow-x: visible; }
.node { flex-direction: row; text-align: left; padding: 0 0 1.75rem 2.9rem; min-width: 0; align-items: flex-start; }
.node::before { top: 0; left: 13px; width: 2px; height: 100%; background: repeating-linear-gradient(180deg, var(--border-strong) 0 6px, transparent 6px 11px); }
.node.is-active::before { background: repeating-linear-gradient(180deg, var(--accent) 0 6px, transparent 6px 11px); }
.node .pad { top: 0; left: 0; }
.node .name { margin-top: 0; margin-left: 0.15rem; }
.node .text { display: flex; flex-direction: column; }
}
.roadmap-footnote { margin-top: 2rem; font-size: 0.95rem; color: var(--text-secondary); border-top: 1px solid var(--border); padding-top: 1.5rem; }
.roadmap-footnote strong { color: var(--text); }
/* ============================================================
14. REVEAL ANIMATION
============================================================ */
.reveal { opacity: 0; transform: translateY(14px); transition: opacity 0.5s ease, transform 0.5s ease; }
.reveal.is-visible { opacity: 1; transform: translateY(0); }
@media (prefers-reduced-motion: reduce) { .reveal { opacity: 1; transform: none; transition: none; } }
/* ============================================================
15. FOOTER
============================================================ */
.site-footer { border-top: 1px solid var(--border); padding-block: 3rem 2rem; margin-top: 2rem; position: relative; overflow: hidden; }
.site-footer::before {
content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px;
background: linear-gradient(90deg, var(--grad-1), var(--grad-2), var(--grad-3), var(--grad-4), var(--grad-5));
}
.footer-grid { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 2rem; }
.footer-brand .mark {
font-family: var(--font-mono); font-weight: 800; font-size: 1.3rem;
background: linear-gradient(135deg, var(--accent), #ec4899); -webkit-background-clip: text; background-clip: text; color: transparent;
}
.footer-logo { max-width: 300px; width: 100%; height: auto; opacity: 0.5; margin-bottom: 0.5rem; }
.footer-brand .sub { color: var(--text-muted); font-size: 0.85rem; margin-top: 0.2rem; }
.footer-motto { font-size: 0.95rem; color: var(--text-secondary); line-height: 1.7; }
.footer-links { display: flex; gap: 1.5rem; }
.footer-links a { text-decoration: none; color: var(--text-secondary); font-size: 0.9rem; font-weight: 600; display: inline-flex; align-items: center; gap: 0.4rem; }
.footer-links a:hover { color: var(--accent); }
.footer-bottom {
margin-top: 2.5rem; padding-top: 1.5rem; border-top: 1px solid var(--border);
font-family: var(--font-mono); font-size: 0.78rem; color: var(--text-muted); text-align: center; letter-spacing: 0.02em;
}
@media print {
.site-header, .theme-toggle, .hamburger, .hero-ctas, .btn, .project-links, .circuit { display: none !important; }
body { background-image: none; color: #000; }
section { padding-block: 1rem; }
a { color: #000; text-decoration: underline; }
.card::before, .project-card::before, .stat::before, .value-chip::before { display: none; }
}
<style>
.article-page {
padding-block: 4rem;
}
.article-content {
max-width: 800px;
margin-inline: auto;
font-size: 1.1rem;
line-height: 1.8;
color: var(--text-secondary);
}
.article-content h1 {
font-size: clamp(2rem, 4vw, 2.75rem);
color: var(--text);
line-height: 1.2;
margin-bottom: 1rem;
font-weight: 800;
letter-spacing: -0.02em;
}
.article-content h2 {
font-size: 1.75rem;
color: var(--text);
margin-top: 3rem;
margin-bottom: 1rem;
font-weight: 700;
}
.article-content h3 {
font-size: 1.25rem;
color: var(--text-muted);
font-weight: 500;
margin-bottom: 2rem;
}
.article-content p {
margin-bottom: 1.5rem;
}
.article-content blockquote {
border-left: 4px solid var(--accent);
padding-left: 1.5rem;
margin-left: 0;
margin-right: 0;
font-style: italic;
font-size: 1.2rem;
color: var(--text);
background: var(--surface);
padding-block: 1rem;
border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
margin-bottom: 1.5rem;
}
.article-content blockquote p:last-child {
margin-bottom: 0;
}
.article-content hr {
border: 0;
height: 1px;
background: var(--border);
margin-block: 3rem;
}
.article-content ul {
list-style: disc;
padding-left: 1.5rem;
margin-bottom: 1.5rem;
}
.article-content li {
margin-bottom: 0.5rem;
}
.article-content pre {
background: var(--surface);
padding: 1.5rem;
border-radius: var(--radius);
border: 1px solid var(--border);
overflow-x: auto;
margin-bottom: 1.5rem;
font-family: var(--font-mono);
font-size: 0.9rem;
}
.article-content code {
font-family: var(--font-mono);
background: var(--surface);
padding: 0.2em 0.4em;
border-radius: 4px;
font-size: 0.9em;
color: var(--accent);
}
.article-content pre code {
background: none;
padding: 0;
color: var(--text);
}
.article-content table {
width: 100%;
border-collapse: collapse;
margin-bottom: 1.5rem;
background: var(--bg-raised);
border-radius: var(--radius);
overflow: hidden;
border: 1px solid var(--border);
}
.article-content th, .article-content td {
padding: 1rem;
text-align: left;
border-bottom: 1px solid var(--border);
}
.article-content th {
background: var(--surface);
font-weight: 600;
color: var(--text);
}
.article-content tr:last-child td {
border-bottom: none;
}
</style>
</style>
</head>
<body>
<a href="#main" class="skip-link">Skip to content</a>
<!-- ICON SPRITE -->
<svg class="icon-sprite" aria-hidden="true">
<defs>
<symbol id="i-key" viewBox="0 0 24 24"><circle cx="8" cy="15" r="4"/><path d="M11 12l9-9M17 6l3 3M14 9l2 2"/></symbol>
<symbol id="i-server" viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="6" rx="1.5"/><rect x="3" y="14" width="18" height="6" rx="1.5"/><circle cx="7" cy="7" r="1" fill="currentColor" stroke="none"/><circle cx="7" cy="17" r="1" fill="currentColor" stroke="none"/></symbol>
<symbol id="i-gauge" viewBox="0 0 24 24"><path d="M4 15a8 8 0 1116 0"/><path d="M12 15l4-5"/><circle cx="12" cy="15" r="1" fill="currentColor" stroke="none"/></symbol>
<symbol id="i-lock" viewBox="0 0 24 24"><rect x="5" y="11" width="14" height="9" rx="2"/><path d="M8 11V7a4 4 0 018 0v4"/></symbol>
<symbol id="i-shield-check" viewBox="0 0 24 24"><path d="M12 3l7 3v6c0 4.5-3 7.5-7 9-4-1.5-7-4.5-7-9V6l7-3z"/><path d="M9 12l2 2 4-4"/></symbol>
<symbol id="i-wrench" viewBox="0 0 24 24"><path d="M14.7 6.3a4 4 0 00-5.4 5.4L4 17v3h3l5.3-5.3a4 4 0 005.4-5.4l-2.5 2.5-2-2 2.5-2.5z"/></symbol>
<symbol id="i-clock" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8.5"/><path d="M12 7v5l3.5 2"/></symbol>
<symbol id="i-cpu" viewBox="0 0 24 24"><rect x="6" y="6" width="12" height="12" rx="1.5"/><path d="M9 3v3M15 3v3M9 18v3M15 18v3M3 9h3M3 15h3M18 9h3M18 15h3"/></symbol>
<symbol id="i-box" viewBox="0 0 24 24"><path d="M12 3l8 4.5v9L12 21l-8-4.5v-9L12 3z"/><path d="M4.5 7.5L12 12l7.5-4.5M12 12v9"/></symbol>
<symbol id="i-database" viewBox="0 0 24 24"><ellipse cx="12" cy="6" rx="7" ry="3"/><path d="M5 6v6c0 1.7 3.1 3 7 3s7-1.3 7-3V6"/><path d="M5 12v6c0 1.7 3.1 3 7 3s7-1.3 7-3v-6"/></symbol>
<symbol id="i-bolt" viewBox="0 0 24 24"><path d="M13 2L4 14h6l-1 8 9-12h-6l1-8z"/></symbol>
<symbol id="i-route" viewBox="0 0 24 24"><circle cx="5" cy="6" r="2.3"/><circle cx="19" cy="18" r="2.3"/><path d="M5 8.3v3a4 4 0 004 4h6a4 4 0 004 4"/></symbol>
<symbol id="i-layers" viewBox="0 0 24 24"><path d="M12 3l9 5-9 5-9-5 9-5z"/><path d="M3 13l9 5 9-5M3 8l9 5 9-5"/></symbol>
<symbol id="i-terminal" viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M7 9l4 3-4 3M13 15h4"/></symbol>
<symbol id="i-monitor" viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="12" rx="1.5"/><path d="M8 20h8M12 16v4"/><path d="M6 12l3-3 2 2 4-4"/></symbol>
<symbol id="i-infinity" viewBox="0 0 24 24"><path d="M7 9a3.5 3.5 0 100 7 3.5 3.5 0 002.9-1.5L12 12l2.1 2.5A3.5 3.5 0 1017 9a3.5 3.5 0 00-2.9 1.5L12 13l-2.1-2.5A3.5 3.5 0 007 9z"/></symbol>
<symbol id="i-chart" viewBox="0 0 24 24"><path d="M4 20V10M10 20V4M16 20v-7M22 20H2"/></symbol>
<symbol id="i-shield" viewBox="0 0 24 24"><path d="M12 3l7 3v6c0 4.5-3 7.5-7 9-4-1.5-7-4.5-7-9V6l7-3z"/></symbol>
<symbol id="i-link" viewBox="0 0 24 24"><path d="M9 15l6-6"/><path d="M11 6l1-1a4 4 0 015.5 5.5l-2 2"/><path d="M13 18l-1 1a4 4 0 01-5.5-5.5l2-2"/></symbol>
<symbol id="i-globe" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8.5"/><path d="M3.5 12h17M12 3.5c2.5 2.3 4 5.3 4 8.5s-1.5 6.2-4 8.5c-2.5-2.3-4-5.3-4-8.5s1.5-6.2 4-8.5z"/></symbol>
<symbol id="i-flag" viewBox="0 0 24 24"><path d="M5 3v18"/><path d="M5 4h13l-3 4 3 4H5"/></symbol>
<symbol id="i-info" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8.5"/><path d="M12 11v5.5M12 8v.01"/></symbol>
<symbol id="i-git" viewBox="0 0 24 24"><circle cx="6" cy="6" r="2.2"/><circle cx="6" cy="18" r="2.2"/><circle cx="18" cy="12" r="2.2"/><path d="M6 8.2v7.6M6 8.2c0 4 3 5.8 6 5.8h4"/></symbol>
</defs>
</svg>
<header class="site-header">
<div class="nav-inner">
<a href="#home" class="brand">
<img src="icon.svg" alt="" class="nav-icon">
NX9
</a>
<nav class="nav-links" id="navLinks" aria-label="Primary">
<a href="/index.html#home" data-nav="home">Home</a>
<a href="/index.html#philosophy" data-nav="philosophy">Philosophy</a>
<a href="/index.html#architecture" data-nav="architecture">Architecture</a>
<a href="/index.html#projects" data-nav="projects">Projects</a>
<a href="/index.html#vision" data-nav="vision">Vision</a>
<a href="/index.html#values" data-nav="values">Values</a>
<a href="/index.html#roadmap" data-nav="roadmap">Roadmap</a>
<a href="case-study.html" target="_blank" class="is-active">Case Study</a>
</nav>
<div class="nav-right">
<button class="theme-toggle" id="themeToggle" aria-label="Toggle color theme">
<span id="themeIcon" aria-hidden="true">◐</span><span id="themeLabel">Theme</span>
</button>
<button class="hamburger" id="hamburger" aria-label="Toggle navigation menu" aria-expanded="false" aria-controls="navLinks">
<span></span>
</button>
</div>
</div>
</header>
<main id="main" class="article-page">
<div class="wrap article-content">
<h1>NX9 Philosophy: Engineering Beyond Frameworks</h1>
<h3><em>A real-world case study in software minimalism, explicit routing, and reduced attack surface</em></h3>
<blockquote>
<p><strong>"The best way to reduce complexity is not to manage more software—it is to deploy less software."</strong></p>
</blockquote>
<hr>
<h1>Introduction</h1>
<p>Modern software engineering often begins with a familiar question:</p>
<blockquote>
<p><strong>"Which framework should we use?"</strong></p>
</blockquote>
<p>NX9 begins with a different question:</p>
<blockquote>
<p><strong>"Do we need one at all?"</strong></p>
</blockquote>
<p>This is not an argument against frameworks.</p>
<p>Frameworks have transformed software development and solved some of the most challenging engineering problems ever encountered.</p>
<p>React revolutionized large-scale user interfaces at Facebook.</p>
<p>Angular addressed Google's enterprise-scale application requirements.</p>
<p>Laravel dramatically improved developer productivity for PHP applications.</p>
<p>Spring Boot simplified enterprise Java development.</p>
<p>Next.js made sophisticated React applications easier to deploy.</p>
<p>These are remarkable engineering achievements.</p>
<p>But they solved <strong>specific engineering problems</strong>.</p>
<p>The question every project should ask is:</p>
<blockquote>
<p><strong>Do we have those same problems?</strong></p>
</blockquote>
<p>A personal website, a self-hosted utility, an authentication service, a URL shortener, or an infrastructure component rarely requires thousands of JavaScript packages, multiple runtimes, extensive middleware chains, complex build pipelines, and enormous dependency trees simply to deliver its intended functionality.</p>
<p>For many projects, complexity becomes the default—not the requirement.</p>
<p>NX9 deliberately chooses another path.</p>
<hr>
<h1>Production Snapshot</h1>
<p>The observations presented in this article come directly from the production logs of <strong>nx9.in</strong> after its first public deployment.</p>
<p>They are <strong>not</strong> the result of a penetration test, laboratory simulation, or synthetic benchmark.</p>
<p>During the observation period:</p>
<ul>
<li>Multiple independent vulnerability scanners began probing the server shortly after public exposure.</li>
<li>Automated requests targeted common framework artifacts, PHP files, WordPress installations, Laravel configuration, Vue projects, Docker deployments, and build-system outputs.</li>
<li>Every vulnerability probe resulted in <strong><code>404 Not Found</code></strong>.</li>
<li>Legitimate visitors—including desktop browsers, Android devices, Twitter/X crawlers, search crawlers, and internal users—continued to access the published resources normally.</li>
</ul>
<p>These observations provide a useful real-world case study of the NX9 engineering philosophy.</p>
<hr>
<h1>Engineering Beyond Frameworks</h1>
<p>NX9 is founded on a simple engineering principle:</p>
<blockquote>
<p><strong>Deploy only the software necessary to solve the problem.</strong></p>
</blockquote>
<p>Nothing more.</p>
<p>Nothing less.</p>
<p>Every project within the NX9 ecosystem follows the same philosophy:</p>
<ul>
<li>Privacy First</li>
<li>Self-Hosted First</li>
<li>Linux Native</li>
<li>Rust Native</li>
<li>Single Binary Applications</li>
<li>Explicit Routing</li>
<li>Minimal Dependencies</li>
<li>Open Source (FOSS)</li>
<li>No Vendor Lock-In</li>
<li>Operational Simplicity</li>
</ul>
<p>Frameworks are not avoided because they are "bad."</p>
<p>They are avoided when they solve problems the application simply does not have.</p>
<p>Every dependency should justify its existence.</p>
<p>Every abstraction should earn its maintenance cost.</p>
<p>Every additional component should provide value greater than the complexity it introduces.</p>
<hr>
<h1>Complexity Has a Cost</h1>
<p>Modern applications are often assembled from enormous dependency trees.</p>
<p>A simple "Hello World" project may involve:</p>
<ul>
<li>thousands of npm packages;</li>
<li>hundreds of transitive dependencies;</li>
<li>multiple build tools;</li>
<li>package managers;</li>
<li>runtime environments;</li>
<li>framework-specific tooling;</li>
<li>automated code generation.</li>
</ul>
<p>Each component is individually useful.</p>
<p>Collectively, they increase operational responsibility.</p>
<p>Every additional dependency must eventually be:</p>
<ul>
<li>installed;</li>
<li>configured;</li>
<li>updated;</li>
<li>audited;</li>
<li>monitored;</li>
<li>patched;</li>
<li>understood.</li>
</ul>
<p>NX9 asks a simple engineering question:</p>
<blockquote>
<p><strong>Can this problem be solved with significantly less software?</strong></p>
</blockquote>
<p>If the answer is yes, simplicity becomes the preferred design.</p>
<hr>
<h1>Real-World Validation</h1>
<p>Shortly after <strong>nx9.in</strong> became publicly accessible, automated scanners began probing the server.</p>
<p>The requests were not random.</p>
<p>They were highly characteristic of Internet-wide reconnaissance targeting common deployment technologies.</p>
<p>Representative examples included:</p>
<pre><code>/.env
/vendor/.env
/wp-admin/
/wp-content/
/phpinfo.php
/vercel.json
/vite.config.ts
/vendors~main.bundle.js
/vue/
/v1/admin/</code></pre>
<p>These examples represent many similar probes observed throughout the production logs.</p>
<p>The scanners were attempting to identify technologies rather than applications.</p>
<hr>
<h1>What the Bots Assumed</h1>
<table><thead><tr><th>Probe</th><th>Likely Assumption</th></tr></thead><tbody>
<tr><td><code>/.env</code></td><td>Laravel / PHP configuration</td></tr>
<tr><td><code>/vendor/.env</code></td><td>Composer project</td></tr>
<tr><td><code>/wp-admin/</code></td><td>WordPress</td></tr>
<tr><td><code>/wp-content/</code></td><td>WordPress plugins</td></tr>
<tr><td><code>/phpinfo.php</code></td><td>PHP runtime</td></tr>
<tr><td><code>vite.config.ts</code></td><td>Vite project</td></tr>
<tr><td><code>vendors~main.bundle.js</code></td><td>Webpack / React build</td></tr>
<tr><td><code>vercel.json</code></td><td>Vercel deployment</td></tr>
<tr><td><code>/vue/.env</code></td><td>Vue project</td></tr>
<tr><td><code>/v1/admin/</code></td><td>Administrative API</td></tr>
The production logs demonstrate a simple reality:</p>
<p><strong>The scanners were not looking for NX9.</strong></p>
<p>They were looking for technologies that dominate today's web.</p>
<p>NX9 simply wasn't one of them.</p>
<hr>
<h1>What Actually Happened</h1>
<p>Every probe produced essentially the same result.</p>
<pre><code>404 Not Found</code></pre>
<p>Not because NX9 blocked the requests.</p>
<p>Not because a Web Application Firewall analyzed malicious behaviour.</p>
<p>Not because an intrusion prevention system intervened.</p>
<p>The requested resources simply did not exist.</p>
<p>This distinction is important.</p>
<p>There is a fundamental difference between software successfully defending itself and software that was never deployed in the first place.</p>
<hr>
<h1>Security Begins Before Deployment</h1>
<p>Security is often associated with firewalls, intrusion detection systems, endpoint protection, and monitoring platforms.</p>
<p>Those remain valuable.</p>
<p>However, architecture itself is also a security decision.</p>
<p>The production deployment contained:</p>
<ul>
<li>no PHP interpreter;</li>
<li>no WordPress;</li>
<li>no Laravel;</li>
<li>no Composer vendor directory;</li>
<li>no Node.js runtime;</li>
<li>no exposed <code>.env</code> files;</li>
<li>no framework-generated administration interfaces;</li>
<li>no debug endpoints;</li>
<li>no unnecessary middleware.</li>
</ul>
<p>Those components were never installed.</p>
<p>Consequently, they were never available for attackers to discover.</p>
<p>This is not security through obscurity.</p>
<p>It is <strong>security through intentional software selection.</strong></p>
<hr>
<h1>Explicit Routing</h1>
<p>One of the defining characteristics of NX9 applications is explicit routing.</p>
<p>Only routes intentionally defined by the developer exist.</p>
<p>Conceptually:</p>
<svg width="100%" height="220" viewBox="0 0 250 220" xmlns="http://www.w3.org/2000/svg" style="max-width: 250px; margin: 1.5rem 0;"><text x="20" y="25" font-family="var(--font-mono)" font-size="14" font-weight="700" fill="var(--accent)">/</text><line x1="24" y1="30" x2="24" y2="60" stroke="var(--border-strong)" stroke-width="2" /><line x1="24" y1="60" x2="50" y2="60" stroke="var(--border-strong)" stroke-width="2" /><text x="60" y="65" font-family="var(--font-mono)" font-size="14" font-weight="600" fill="var(--text)">/projects</text><line x1="24" y1="60" x2="24" y2="80" stroke="var(--border-strong)" stroke-width="2" /><line x1="24" y1="70" x2="24" y2="100" stroke="var(--border-strong)" stroke-width="2" /><line x1="24" y1="100" x2="50" y2="100" stroke="var(--border-strong)" stroke-width="2" /><text x="60" y="105" font-family="var(--font-mono)" font-size="14" font-weight="600" fill="var(--text)">/about</text><line x1="24" y1="100" x2="24" y2="120" stroke="var(--border-strong)" stroke-width="2" /><line x1="24" y1="110" x2="24" y2="140" stroke="var(--border-strong)" stroke-width="2" /><line x1="24" y1="140" x2="50" y2="140" stroke="var(--border-strong)" stroke-width="2" /><text x="60" y="145" font-family="var(--font-mono)" font-size="14" font-weight="600" fill="var(--text)">/contact</text><line x1="24" y1="140" x2="24" y2="160" stroke="var(--border-strong)" stroke-width="2" /><line x1="24" y1="150" x2="24" y2="180" stroke="var(--border-strong)" stroke-width="2" /><line x1="24" y1="180" x2="50" y2="180" stroke="var(--border-strong)" stroke-width="2" /><text x="60" y="185" font-family="var(--font-mono)" font-size="14" font-weight="600" fill="var(--text)">404 (Fallback)</text></svg>
<p>There is no directory discovery.</p>
<p>There is no automatic controller resolution.</p>
<p>There is no runtime searching for matching files.</p>
<p>If a route was never implemented, it simply cannot be reached.</p>
<p>Unknown URLs immediately terminate at the application's fallback handler.</p>
<hr>
<h1>A Smaller Stack</h1>
<p>Many modern web applications resemble:</p>
<svg width="100%" height="476" viewBox="0 0 260 476" xmlns="http://www.w3.org/2000/svg" style="max-width: 300px; margin: 1.5rem 0;">
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="var(--accent)" />
</marker>
</defs>
<rect x="20.0" y="10" width="220" height="36" rx="18" fill="var(--bg-raised)" stroke="var(--border-strong)" stroke-width="1.5" /><text x="130.0" y="32.0" font-family="var(--font-ui)" font-size="13" font-weight="600" fill="var(--text)" text-anchor="middle">Internet</text><line x1="130.0" y1="46" x2="130.0" y2="66" stroke="var(--accent)" stroke-width="2" marker-end="url(#arrow)" /><rect x="20.0" y="70" width="220" height="36" rx="6" fill="var(--surface)" stroke="var(--border)" stroke-width="1" /><text x="130.0" y="92.0" font-family="var(--font-ui)" font-size="13" font-weight="600" fill="var(--text)" text-anchor="middle">Reverse Proxy</text><line x1="130.0" y1="106" x2="130.0" y2="126" stroke="var(--accent)" stroke-width="2" marker-end="url(#arrow)" /><rect x="20.0" y="130" width="220" height="36" rx="6" fill="var(--surface)" stroke="var(--border)" stroke-width="1" /><text x="130.0" y="152.0" font-family="var(--font-ui)" font-size="13" font-weight="600" fill="var(--text)" text-anchor="middle">Runtime</text><line x1="130.0" y1="166" x2="130.0" y2="186" stroke="var(--accent)" stroke-width="2" marker-end="url(#arrow)" /><rect x="20.0" y="190" width="220" height="36" rx="6" fill="var(--surface)" stroke="var(--border)" stroke-width="1" /><text x="130.0" y="212.0" font-family="var(--font-ui)" font-size="13" font-weight="600" fill="var(--text)" text-anchor="middle">Framework</text><line x1="130.0" y1="226" x2="130.0" y2="246" stroke="var(--accent)" stroke-width="2" marker-end="url(#arrow)" /><rect x="20.0" y="250" width="220" height="36" rx="6" fill="var(--surface)" stroke="var(--border)" stroke-width="1" /><text x="130.0" y="272.0" font-family="var(--font-ui)" font-size="13" font-weight="600" fill="var(--text)" text-anchor="middle">Middleware</text><line x1="130.0" y1="286" x2="130.0" y2="306" stroke="var(--accent)" stroke-width="2" marker-end="url(#arrow)" /><rect x="20.0" y="310" width="220" height="36" rx="6" fill="var(--surface)" stroke="var(--border)" stroke-width="1" /><text x="130.0" y="332.0" font-family="var(--font-ui)" font-size="13" font-weight="600" fill="var(--text)" text-anchor="middle">Plugins</text><line x1="130.0" y1="346" x2="130.0" y2="366" stroke="var(--accent)" stroke-width="2" marker-end="url(#arrow)" /><rect x="20.0" y="370" width="220" height="36" rx="6" fill="var(--surface)" stroke="var(--border)" stroke-width="1" /><text x="130.0" y="392.0" font-family="var(--font-ui)" font-size="13" font-weight="600" fill="var(--text)" text-anchor="middle">Packages</text><line x1="130.0" y1="406" x2="130.0" y2="426" stroke="var(--accent)" stroke-width="2" marker-end="url(#arrow)" /><rect x="20.0" y="430" width="220" height="36" rx="6" fill="var(--surface)" stroke="var(--border)" stroke-width="1" /><text x="130.0" y="452.0" font-family="var(--font-ui)" font-size="13" font-weight="600" fill="var(--text)" text-anchor="middle">Application</text></svg>
<p>NX9 deliberately reduces the stack.</p>
<svg width="100%" height="296" viewBox="0 0 260 296" xmlns="http://www.w3.org/2000/svg" style="max-width: 300px; margin: 1.5rem 0;">
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="var(--accent)" />
</marker>
</defs>
<rect x="20.0" y="10" width="220" height="36" rx="18" fill="var(--bg-raised)" stroke="var(--border-strong)" stroke-width="1.5" /><text x="130.0" y="32.0" font-family="var(--font-ui)" font-size="13" font-weight="600" fill="var(--text)" text-anchor="middle">Internet</text><line x1="130.0" y1="46" x2="130.0" y2="66" stroke="var(--accent)" stroke-width="2" marker-end="url(#arrow)" /><rect x="20.0" y="70" width="220" height="36" rx="6" fill="var(--surface)" stroke="var(--border)" stroke-width="1" /><text x="130.0" y="92.0" font-family="var(--font-ui)" font-size="13" font-weight="600" fill="var(--text)" text-anchor="middle">Nginx</text><line x1="130.0" y1="106" x2="130.0" y2="126" stroke="var(--accent)" stroke-width="2" marker-end="url(#arrow)" /><rect x="20.0" y="130" width="220" height="36" rx="6" fill="var(--surface)" stroke="var(--border)" stroke-width="1" /><text x="130.0" y="152.0" font-family="var(--font-ui)" font-size="13" font-weight="600" fill="var(--text)" text-anchor="middle">Rust Binary</text><line x1="130.0" y1="166" x2="130.0" y2="186" stroke="var(--accent)" stroke-width="2" marker-end="url(#arrow)" /><rect x="20.0" y="190" width="220" height="36" rx="6" fill="var(--surface)" stroke="var(--border)" stroke-width="1" /><text x="130.0" y="212.0" font-family="var(--font-ui)" font-size="13" font-weight="600" fill="var(--text)" text-anchor="middle">Explicit Route Table</text><line x1="130.0" y1="226" x2="130.0" y2="246" stroke="var(--accent)" stroke-width="2" marker-end="url(#arrow)" /><rect x="20.0" y="250" width="220" height="36" rx="6" fill="var(--surface)" stroke="var(--border)" stroke-width="1" /><text x="130.0" y="272.0" font-family="var(--font-ui)" font-size="13" font-weight="600" fill="var(--text)" text-anchor="middle">Application Logic</text></svg>
<p>The objective is not minimalism for its own sake.</p>
<p>The objective is proportional engineering.</p>
<hr>
<h1>Why NX9 Chose This Path</h1>
<p>The previous comparison is not intended to suggest that one architecture is universally superior.</p>
<p>Frameworks remain exceptional engineering tools.</p>
<p>React solved Facebook's problems.</p>
<p>Angular solved Google's.</p>
<p>Laravel dramatically improved PHP development.</p>
<p>Spring Boot transformed enterprise Java.</p>
<p>Those achievements deserve recognition.</p>
<p>NX9 simply asks a different question:</p>
<blockquote>
<p><strong>Does this framework solve <em>our</em> problem?</strong></p>
</blockquote>
<p>If the answer is yes, use it.</p>
<p>If the answer is no, adding it merely increases long-term complexity.</p>
<p>Engineering is not about choosing the most popular technology.</p>
<p>It is about choosing the most appropriate one.</p>
<hr>
<h1>The Production Logs Tell a Story</h1>
<p>The production logs describe a remarkably ordinary day on the public Internet.</p>
<svg width="100%" height="356" viewBox="0 0 260 356" xmlns="http://www.w3.org/2000/svg" style="max-width: 300px; margin: 1.5rem 0;">
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="var(--accent)" />
</marker>
</defs>
<rect x="20.0" y="10" width="220" height="36" rx="18" fill="var(--bg-raised)" stroke="var(--border-strong)" stroke-width="1.5" /><text x="130.0" y="32.0" font-family="var(--font-ui)" font-size="13" font-weight="600" fill="var(--text)" text-anchor="middle">Public deployment</text><line x1="130.0" y1="46" x2="130.0" y2="66" stroke="var(--accent)" stroke-width="2" marker-end="url(#arrow)" /><rect x="20.0" y="70" width="220" height="36" rx="6" fill="var(--surface)" stroke="var(--border)" stroke-width="1" /><text x="130.0" y="92.0" font-family="var(--font-ui)" font-size="13" font-weight="600" fill="var(--text)" text-anchor="middle">Automated vulnerability scanners</text><line x1="130.0" y1="106" x2="130.0" y2="126" stroke="var(--accent)" stroke-width="2" marker-end="url(#arrow)" /><rect x="20.0" y="130" width="220" height="36" rx="6" fill="var(--surface)" stroke="var(--border)" stroke-width="1" /><text x="130.0" y="152.0" font-family="var(--font-ui)" font-size="13" font-weight="600" fill="var(--text)" text-anchor="middle">Search engine and social crawlers</text><line x1="130.0" y1="166" x2="130.0" y2="186" stroke="var(--accent)" stroke-width="2" marker-end="url(#arrow)" /><rect x="20.0" y="190" width="220" height="36" rx="6" fill="var(--surface)" stroke="var(--border)" stroke-width="1" /><text x="130.0" y="212.0" font-family="var(--font-ui)" font-size="13" font-weight="600" fill="var(--text)" text-anchor="middle">Twitter/X preview generation</text><line x1="130.0" y1="226" x2="130.0" y2="246" stroke="var(--accent)" stroke-width="2" marker-end="url(#arrow)" /><rect x="20.0" y="250" width="220" height="36" rx="6" fill="var(--surface)" stroke="var(--border)" stroke-width="1" /><text x="130.0" y="272.0" font-family="var(--font-ui)" font-size="13" font-weight="600" fill="var(--text)" text-anchor="middle">Real desktop and mobile visitors</text><line x1="130.0" y1="286" x2="130.0" y2="306" stroke="var(--accent)" stroke-width="2" marker-end="url(#arrow)" /><rect x="20.0" y="310" width="220" height="36" rx="6" fill="var(--surface)" stroke="var(--border)" stroke-width="1" /><text x="130.0" y="332.0" font-family="var(--font-ui)" font-size="13" font-weight="600" fill="var(--text)" text-anchor="middle">Additional vulnerability scanners</text></svg>
<p>The site remained fully functional for legitimate users while automated scanners repeatedly searched for technologies that simply were not present.</p>
<hr>
<h1>Less Software Means Less Responsibility</h1>
<p>Every dependency becomes another responsibility.</p>
<p>Someone must:</p>
<ul>
<li>update it;</li>
<li>audit it;</li>
<li>patch it;</li>
<li>monitor it;</li>
<li>understand it.</li>
</ul>
<p>Every framework introduces conventions.</p>
<p>Every plugin introduces assumptions.</p>
<p>Every runtime introduces operational complexity.</p>
<p>None of these are inherently negative.</p>
<p>They are engineering trade-offs.</p>
<p>NX9 deliberately chooses different trade-offs.</p>
<p>Smaller deployments.</p>
<p>Fewer dependencies.</p>
<p>Explicit behaviour.</p>
<p>Simpler operations.</p>
<hr>
<h1>Non-Goals</h1>
<p>NX9 does <strong>not</strong> attempt to:</p>
<ul>
<li>replace every web framework;</li>
<li>eliminate JavaScript;</li>
<li>discourage modern development practices;</li>
<li>claim that Rust is immune to vulnerabilities;</li>
<li>promote security through obscurity.</li>
</ul>
<p>NX9 simply argues that software should be proportional to the problem being solved.</p>
<hr>
<h1>Conclusion</h1>
<p>This philosophy extends beyond a single website.</p>
<p>Every NX9 project—whether it is a URL shortener, an authentication service, a digital timestamping platform, or future infrastructure components—begins with the same engineering question:</p>
<blockquote>
<p><strong>What is the smallest amount of software required to solve this problem well?</strong></p>
</blockquote>
<p>The answer will not always be the same.</p>
<p>Some problems genuinely require sophisticated frameworks.</p>
<p>Many do not.</p>
<p>NX9 exists to explore that second category.</p>
<p>Not because minimalism is fashionable.</p>
<p>Not because frameworks are flawed.</p>
<p>But because simplicity remains one of the most effective engineering tools available.</p>
<p>The production logs provide a practical demonstration of this philosophy.</p>
<p>The Internet searched for PHP.</p>
<p>It searched for WordPress.</p>
<p>It searched for Laravel.</p>
<p>It searched for Vue.</p>
<p>It searched for Node.js deployment artifacts.</p>
<p>It searched for technologies that have become commonplace.</p>
<p>What it found instead was a deliberately minimal Rust application exposing only the functionality it was designed to provide.</p>
<p>That outcome was not accidental.</p>
<p>It was the result of an engineering decision made long before the first HTTP request reached the server.</p>
<p><strong>Build only what you need.</strong></p>
<p><strong>Deploy only what you trust.</strong></p>
<p><strong>Maintain only what you own.</strong></p>
<p>Because every component you choose <strong>not</strong> to deploy is one less component to configure, patch, monitor, audit—and one less component available to be targeted.</p>
<p><strong>That is the NX9 philosophy.</strong></p></tbody></table>
</div>
</main>
<footer class="site-footer">
<div class="wrap">
<div class="footer-grid">
<div class="footer-brand">
<img src="logo.svg" alt="NX9 Logo" class="footer-logo">
<div class="sub">Next Generation 9</div>
</div>
<p class="footer-motto">Software people can own,<br>understand,<br>and control.<br><br><strong>Always Free. Always Open. Always Yours.</strong></p>
<nav class="footer-links" aria-label="Repository links">
<a href="https://codeberg.org/thakares" target="_blank" rel="noopener noreferrer"><svg class="icon" style="width:16px;height:16px"><use href="#i-git"/></svg> Codeberg</a>
<a href="https://github.com/thakares?tab=repositories" target="_blank" rel="noopener noreferrer"><svg class="icon" style="width:16px;height:16px"><use href="#i-link"/></svg> GitHub</a>
</nav>
</div>
<div class="footer-bottom">© <span id="year"></span> NX9 — an open-source ecosystem by Sunil Thakare. MIT / Apache-2.0.</div>
</div>
</footer>
<script>
(function () {
"use strict";
/* ============================================================
THEME
============================================================ */
const root = document.documentElement;
const themeToggle = document.getElementById("themeToggle");
const themeIcon = document.getElementById("themeIcon");
const themeLabel = document.getElementById("themeLabel");
const STORAGE_KEY = "nx9-theme";
function applyTheme(theme) {
root.setAttribute("data-theme", theme);
themeIcon.textContent = theme === "dark" ? "●" : "○";
themeLabel.textContent = theme === "dark" ? "Dark" : "Light";
themeToggle.setAttribute("aria-pressed", theme === "dark" ? "true" : "false");
}
function initTheme() {
const stored = localStorage.getItem(STORAGE_KEY);
if (stored === "light" || stored === "dark") { applyTheme(stored); return; }
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
applyTheme(prefersDark ? "dark" : "light");
}
themeToggle.addEventListener("click", function () {
const current = root.getAttribute("data-theme");
const next = current === "dark" ? "light" : "dark";
applyTheme(next);
localStorage.setItem(STORAGE_KEY, next);
});
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function (e) {
if (!localStorage.getItem(STORAGE_KEY)) applyTheme(e.matches ? "dark" : "light");
});
initTheme();
/* ============================================================
MOBILE NAV
============================================================ */
const hamburger = document.getElementById("hamburger");
const navLinks = document.getElementById("navLinks");
hamburger.addEventListener("click", function () {
const isOpen = navLinks.classList.toggle("is-open");
hamburger.setAttribute("aria-expanded", isOpen ? "true" : "false");
});
navLinks.querySelectorAll("a").forEach(function (link) {
link.addEventListener("click", function () {
navLinks.classList.remove("is-open");
hamburger.setAttribute("aria-expanded", "false");
});
});
/* ============================================================
ICON HELPER
============================================================ */
function iconSvg(id) {
return '<svg class="icon"><use href="#' + id + '"/></svg>';
}
/* ============================================================
DATA: DESIGN PHILOSOPHY
============================================================ */
const philosophy = [
{ icon: "i-key", grad: 1, glow: "--glow-1", title: "Operator Ownership", body: "The operator owns the binaries, the configuration, the databases, the backups, and the encryption keys. No service depends on proprietary APIs or cloud-hosted control planes." },
{ icon: "i-server", grad: 6, glow: "--glow-6", title: "Self-Hosting First", body: "Every decision begins with one question: \u201cCan this be deployed and operated by a single administrator?\u201d If it needs Kubernetes or a managed database, the design is reconsidered." },
{ icon: "i-gauge", grad: 3, glow: "--glow-3", title: "Simplicity Over Complexity", body: "One binary. One configuration. One SQLite database. One administrator. Simple systems are easier to understand, secure, and recover." },
{ icon: "i-lock", grad: 4, glow: "--glow-4", title: "Privacy by Default", body: "Applications never assume cloud connectivity, analytics collection, telemetry uploads, or third-party tracking. Users decide what information leaves their infrastructure." },
{ icon: "i-shield-check", grad: 5, glow: "--glow-5", title: "Security by Design", body: "Argon2id, Ed25519, BLAKE3, RBAC, CSRF protection, and audit logs are embedded throughout the stack \u2014 not added later." },
{ icon: "i-wrench", grad: 2, glow: "--glow-2", title: "Operational Excellence", body: "Diagnostics, backups, restore procedures, migration tools, CLI administration, and documentation, in every project, from day one." },
{ icon: "i-clock", grad: 7, glow: "--glow-7", title: "Long-Term Stability", body: "NX9 intentionally avoids dependency churn. The goal is software that remains understandable and maintainable years into the future." },
{ icon: "i-git", grad: 4, glow: "--glow-4", title: "Open Source First", body: "Every NX9 codebase is 100% open source under permissive licenses. You have the fundamental right to inspect, build, and modify the software." },
{ icon: "i-infinity", grad: 5, glow: "--glow-5", title: "Zero Vendor Lock-In", body: "All data is stored in standard SQLite files, configurations are plain text, and architectures strictly avoid proprietary integrations." }
];
const philosophyGrid = document.getElementById("philosophyGrid");
philosophy.forEach(function (p) {
const card = document.createElement("article");
card.className = "card reveal";
card.style.setProperty("--card-grad", "var(--grad-" + p.grad + ")");
card.style.setProperty("--card-glow", "var(" + p.glow + ")");
card.innerHTML =
'<div class="icon-badge">' + iconSvg(p.icon) + '</div>' +
'<h3>' + p.title + '</h3>' +
'<p>' + p.body + '</p>';
philosophyGrid.appendChild(card);
});
/* ============================================================
DATA: ARCHITECTURAL PILLARS
============================================================ */
const architecture = [
{ icon: "i-cpu", grad: 1, glow: "--glow-1", title: "Pure Rust", body: "Memory safety, zero-cost abstractions, and fearless concurrency. Rust 2021 Edition, release-mode optimization, no runtime interpreter.", tag: "~10\u201312 MB per binary" },
{ icon: "i-box", grad: 6, glow: "--glow-6", title: "Single Binary Deployment", body: "One executable contains the HTTP server, business logic, auth, migrations, CLI, and templates. No JVM, no Node.js, no Python, no app server.", tag: "cargo build --release" },
{ icon: "i-database", grad: 5, glow: "--glow-5", title: "SQLite First", body: "ACID transactions, WAL concurrency, zero administration, and portable files. Several projects isolate data across multiple databases for tenant isolation.", tag: "users.db \u00b7 system.db \u00b7 content.db" },
{ icon: "i-bolt", grad: 3, glow: "--glow-3", title: "Tokio Async Runtime", body: "Asynchronous I/O and lightweight tasks power web servers, DNS resolution, and background workers with high concurrency.", tag: "async / await" },
{ icon: "i-route", grad: 4, glow: "--glow-4", title: "Axum Web Layer", body: "Routing, middleware, REST APIs, HTML rendering, authentication, and sessions \u2014 integrated naturally with Tokio and Rust's type system.", tag: "HTTP \u00b7 middleware \u00b7 sessions" },
{ icon: "i-layers", grad: 2, glow: "--glow-2", title: "Layered Architecture", body: "auth / cli / db / handlers / jobs / services / templates / utils / web \u2014 each layer owns one responsibility, for easier testing and lower coupling.", tag: "src/ layout" },
{ icon: "i-terminal", grad: 7, glow: "--glow-7", title: "CLI-First Operations", body: "serve \u00b7 doctor \u00b7 backup \u00b7 restore \u00b7 migrate \u00b7 create-admin \u00b7 init \u2014 every service is administrable headless, over SSH, from a script.", tag: "automation-friendly" },
{ icon: "i-shield", grad: 1, glow: "--glow-1", title: "Security Stack", body: "Argon2id password hashing, Ed25519 signatures, BLAKE3 hashing, CSRF protection, RBAC, and hardened compiler flags \u2014 RELRO, PIE, least privilege.", tag: "defense in depth" },
{ icon: "i-monitor", grad: 6, glow: "--glow-6", title: "Operational Tooling", body: "Health checks, migration verification, automatic backups, restore tools, Docker support, systemd units, and structured logging, out of the box.", tag: "diagnostics \u00b7 systemd \u00b7 docker" }
];
const architectureGrid = document.getElementById("architectureGrid");
architecture.forEach(function (a) {
const card = document.createElement("article");
card.className = "card reveal";
card.style.setProperty("--card-grad", "var(--grad-" + a.grad + ")");
card.style.setProperty("--card-glow", "var(" + a.glow + ")");
card.innerHTML =
'<div class="icon-badge">' + iconSvg(a.icon) + '</div>' +
'<h3>' + a.title + '</h3>' +
'<p>' + a.body + '</p>' +
'<span class="card-tag">' + a.tag + '</span>';
architectureGrid.appendChild(card);
});
/* ============================================================
DATA: SECURITY
============================================================ */
const security = [
{ icon: "i-shield-check", grad: 4, glow: "--glow-4", title: "Argon2id Hashing", body: "Memory-hard, CPU-hard password hashing by default for all user credentials." },
{ icon: "i-key", grad: 1, glow: "--glow-1", title: "Ed25519 Signatures", body: "Fast, secure public-key cryptography for tokens and inter-service authentication." },
{ icon: "i-lock", grad: 6, glow: "--glow-6", title: "Strict RBAC", body: "Role-Based Access Control enforced at the middleware layer before business logic executes." },
{ icon: "i-shield", grad: 5, glow: "--glow-5", title: "CSRF & Security Headers", body: "Double-submit cookies, strict transport security, and hardened Content Security Policies built-in." }
];
const securityGrid = document.getElementById("securityGrid");
security.forEach(function (s) {
const card = document.createElement("article");
card.className = "card reveal";
card.style.setProperty("--card-grad", "var(--grad-" + s.grad + ")");
card.style.setProperty("--card-glow", "var(" + s.glow + ")");
card.innerHTML =
'<div class="icon-badge">' + iconSvg(s.icon) + '</div>' +
'<h3>' + s.title + '</h3>' +
'<p>' + s.body + '</p>';
securityGrid.appendChild(card);
});
/* ============================================================
DATA: POSITIONING
============================================================ */
const positioningBody = document.getElementById("positioningBody");
const posData = [
{ bad: "Requires Kubernetes & Helm", good: "Deployed via a single binary or systemd" },
{ bad: "Hidden telemetry and usage analytics", good: "Zero tracking, completely air-gapped capable" },
{ bad: "1GB+ RAM for a 'Hello World' microservice", good: "10-20MB RAM for a high-traffic production service" },
{ bad: "Forced cloud subscriptions", good: "Your hardware, your data, your rules" },
{ bad: "Complex web of dependencies", good: "Static binaries with SQLite built-in" }
];
posData.forEach(p => {
positioningBody.innerHTML += `<tr><td>${p.bad}</td><td>${p.good}</td></tr>`;
});
/* ============================================================
DATA: PROJECTS
============================================================ */
const projectGrid = document.getElementById("projectGrid");
const projects = [
{
title: "nx9-url-shortener",
desc: "A lightweight, self-hosted URL management platform. Combines URL shortening, analytics, QR codes, password protection, and API automation with zero external dependencies.",
status: "STABLE",
icon: "i-link",
tech: ["Rust", "SQLite", "Axum", "Askama"],
grad: 2, glow: "--glow-2",
link: "https://codeberg.org/thakares/nx9-url-shortener",
github: "https://github.com/thakares/nx9-url-shortener"
},
{
title: "nx9-auth",
desc: "Identity and Access Management (IAM) service. Provides authentication, authorization, session management, and RBAC in a single incredibly fast deployable binary.",
status: "BETA",
icon: "i-lock",
tech: ["Rust", "SQLite", "Security"],
grad: 4, glow: "--glow-4",
link: "https://codeberg.org/thakares/nx9-auth",
github: "https://github.com/thakares/nx9-auth"
},
{
title: "nx9-dns-server",
desc: "High-performance, fully RFC-compliant authoritative DNS server leveraging modern async networking and a robust SQLite backend.",
status: "ALPHA",
icon: "i-globe",
tech: ["Rust", "DNS", "Async"],
grad: 6, glow: "--glow-6",
link: "https://codeberg.org/thakares/nx9-dns-server",
github: "https://github.com/thakares/nx9-dns-server"
},
{
title: "nx9-chronoseal-rs",
desc: "Privacy-first browser attestation framework for anti-bot and anti-AI scraping. Uses Ed25519 heartbeat chains and WASM attestation without tracking users.",
status: "STABLE",
icon: "i-shield",
tech: ["Rust", "WASM", "Ed25519"],
grad: 5, glow: "--glow-5",
link: "https://codeberg.org/thakares/nx9-chronoseal-rs",
github: "https://github.com/thakares/nx9-chronoseal-rs"
}
];
projects.forEach(p => {
projectGrid.innerHTML += `
<div class="project-card reveal" style="--card-grad: var(--grad-${p.grad}); --card-glow: var(${p.glow})">
<div class="project-card-head">
<div class="project-title">
<div class="icon-badge">${iconSvg(p.icon)}</div>
<h3>${p.title}</h3>
</div>
<span class="status-badge" style="background: var(--grad-${p.grad === 5 ? 5 : p.grad === 4 ? 4 : p.grad === 6 ? 6 : 2})">${p.status}</span>
</div>
<p class="desc">${p.desc}</p>
<div class="tech-badges">
${p.tech.map(t => `<span class="tech-badge" style="background: var(--grad-${p.grad})">${t}</span>`).join("")}
</div>
<div class="project-links">
<a href="${p.link}" target="_blank" rel="noopener noreferrer" class="btn btn-sm btn-outline"><svg class="icon" style="width:14px;height:14px"><use href="#i-git"/></svg> Codeberg</a>
<a href="${p.github}" target="_blank" rel="noopener noreferrer" class="btn btn-sm btn-outline"><svg class="icon" style="width:14px;height:14px"><use href="#i-link"/></svg> GitHub</a>
</div>
</div>
`;
});
/* ============================================================
DATA: STATS
============================================================ */
const statsGrid = document.getElementById("statsGrid");
const stats = [
{ num: "0", label: "External Dependencies", grad: 1 },
{ num: "1", label: "Binary to Deploy", grad: 6 },
{ num: "9", label: "Core Projects", grad: 4 },
{ num: "<15MB", label: "RAM per Service", grad: 5 }
];
stats.forEach(s => {
statsGrid.innerHTML += `
<div class="stat reveal" style="--card-grad: var(--grad-${s.grad})">
<span class="num">${s.num}</span>
<span class="label">${s.label}</span>
</div>
`;
});
/* ============================================================
DATA: VALUES
============================================================ */
const valueGrid = document.getElementById("valueGrid");
const values = [
{ num: "01", text: "User Ownership", grad: 1, glow: "--glow-1" },
{ num: "02", text: "Absolute Privacy", grad: 2, glow: "--glow-2" },
{ num: "03", text: "Open Source", grad: 3, glow: "--glow-3" },
{ num: "04", text: "Simplicity First", grad: 4, glow: "--glow-4" },
{ num: "05", text: "CLI Automation", grad: 5, glow: "--glow-5" },
{ num: "06", text: "Open Standards", grad: 6, glow: "--glow-6" },
{ num: "07", text: "Long-term Stability", grad: 7, glow: "--glow-7" },
{ num: "08", text: "Linux Native", grad: 1, glow: "--glow-1" },
{ num: "09", text: "Zero Tracking", grad: 2, glow: "--glow-2" },
{ num: "10", text: "No Vendor Lock", grad: 3, glow: "--glow-3" },
{ num: "11", text: "Performant", grad: 4, glow: "--glow-4" },
{ num: "12", text: "Understandable", grad: 5, glow: "--glow-5" }
];
values.forEach(v => {
valueGrid.innerHTML += `
<div class="value-chip reveal" style="--card-grad: var(--grad-${v.grad}); --card-glow: var(${v.glow})">
<span class="n">${v.num}</span>
<span class="t">${v.text}</span>
</div>
`;
});
/* ============================================================
DATA: ROADMAP
============================================================ */
const circuit = document.getElementById("circuit");
const roadmap = [
{ num: "01", name: "ChronoSeal", state: "STABLE", active: true },
{ num: "02", name: "DNS Server", state: "ALPHA", active: true },
{ num: "03", name: "Auth", state: "BETA", active: true },
{ num: "04", name: "URL Shortener", state: "STABLE", active: true },
{ num: "05", name: "Project 5", state: "PLANNED", active: false },
{ num: "06", name: "Project 6", state: "PLANNED", active: false },
{ num: "07", name: "Project 7", state: "PLANNED", active: false },
{ num: "08", name: "Project 8", state: "PLANNED", active: false },
{ num: "09", name: "Project 9", state: "PLANNED", active: false }
];
roadmap.forEach(r => {
circuit.innerHTML += `
<div class="node ${r.active ? 'is-active' : ''} reveal">
<div class="pad">${r.num}</div>
<div class="text">
<div class="name">${r.name}</div>
<div class="state">${r.state}</div>
</div>
</div>
`;
});
/* ============================================================
REVEAL ANIMATIONS
============================================================ */
const observerOptions = {
root: null,
rootMargin: "0px",
threshold: 0.1
};
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add("is-visible");
observer.unobserve(entry.target);
}
});
}, observerOptions);
document.querySelectorAll(".reveal").forEach(el => observer.observe(el));
// Set copyright year
document.getElementById("year").textContent = new Date().getFullYear();
})();
</script>
</body>
</html>