Add ChronoSeal product website

This commit is contained in:
thakares committed 2026-06-05 12:40:10 +05:30
1 parent 6c11495892
commit 1e038901b3
33 files changed
+6352

No files matched your search

+184
View File
@@ -0,0 +1,184 @@
/* ============================================================
ChronoSeal Website — app.js
Core runtime: header scroll, mobile nav, scroll animations,
code copy, back-to-top, keyboard shortcuts
============================================================ */
(function () {
'use strict';
/* ---- Header scroll state ---- */
var header = document.querySelector('.navbar');
if (header) {
var onScroll = function () {
header.classList.toggle('scrolled', window.scrollY > 20);
};
window.addEventListener('scroll', onScroll, { passive: true });
onScroll();
}
/* ---- Enhanced Mobile nav toggle ---- */
var toggle = document.querySelector('.nav-toggle');
var navLinks = document.querySelector('.nav-links');
if (toggle && navLinks) {
var menuIcon = toggle.querySelector('i');
toggle.addEventListener('click', function () {
var isActive = navLinks.classList.contains('active');
if (isActive) {
navLinks.classList.remove('active');
if (menuIcon) {
menuIcon.classList.remove('fa-times');
menuIcon.classList.add('fa-bars');
}
} else {
navLinks.classList.add('active');
if (menuIcon) {
menuIcon.classList.remove('fa-bars');
menuIcon.classList.add('fa-times');
}
}
});
// Close nav on link click
navLinks.querySelectorAll('a').forEach(function (a) {
a.addEventListener('click', function () {
navLinks.classList.remove('active');
if (menuIcon) {
menuIcon.classList.remove('fa-times');
menuIcon.classList.add('fa-bars');
}
});
});
}
/* ---- Doc sidebar mobile toggle ---- */
var sidebarToggle = document.querySelector('.doc-sidebar-toggle');
var sidebar = document.querySelector('.doc-sidebar');
if (sidebarToggle && sidebar) {
sidebarToggle.addEventListener('click', function () {
sidebar.classList.toggle('open');
});
// Close sidebar on link click (mobile)
sidebar.querySelectorAll('.doc-nav-item').forEach(function (a) {
a.addEventListener('click', function () {
if (window.innerWidth <= 900) sidebar.classList.remove('open');
});
});
}
/* ---- Intersection Observer for Scroll Animations ---- */
if ('IntersectionObserver' in window) {
var observerOptions = { threshold: 0.1, rootMargin: '0px 0px -50px 0px' };
var observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
entry.target.classList.add('in-view');
observer.unobserve(entry.target);
}
});
}, observerOptions);
// Observe all animated elements
document.querySelectorAll('.animate, .card, .stat-card, .step').forEach(function (el) {
if (!el.classList.contains('animate')) {
el.classList.add('animate');
}
observer.observe(el);
});
}
/* ---- Code block copy buttons ---- */
document.querySelectorAll('.code-copy-btn').forEach(function (btn) {
btn.addEventListener('click', function () {
var pre = btn.closest('.code-block').querySelector('pre');
if (!pre) return;
var text = pre.textContent;
if (navigator.clipboard) {
navigator.clipboard.writeText(text).then(function () {
btn.textContent = 'Copied!';
setTimeout(function () { btn.textContent = 'Copy'; }, 1500);
});
} else {
// Fallback
var ta = document.createElement('textarea');
ta.value = text;
ta.style.cssText = 'position:fixed;left:-999px';
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
document.body.removeChild(ta);
btn.textContent = 'Copied!';
setTimeout(function () { btn.textContent = 'Copy'; }, 1500);
}
});
});
/* ---- Back to top ---- */
var btt = document.querySelector('.back-to-top');
if (btt) {
window.addEventListener('scroll', function () {
btt.classList.toggle('visible', window.scrollY > 400);
}, { passive: true });
btt.addEventListener('click', function (e) {
e.preventDefault();
window.scrollTo({ top: 0, behavior: 'smooth' });
});
}
/* ---- Keyboard shortcut: / or Ctrl+K for search ---- */
document.addEventListener('keydown', function (e) {
if (e.key === '/' && !isInput(e.target)) {
e.preventDefault();
if (typeof ChronoSearch !== 'undefined') ChronoSearch.open();
}
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
e.preventDefault();
if (typeof ChronoSearch !== 'undefined') ChronoSearch.open();
}
if (e.key === 'Escape') {
if (typeof ChronoSearch !== 'undefined') ChronoSearch.close();
}
});
function isInput(el) {
var tag = el.tagName;
return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || el.isContentEditable;
}
/* ---- Nav dropdown (desktop hover + mobile tap) ---- */
document.querySelectorAll('.nav-dropdown').forEach(function (dd) {
var trigger = dd.querySelector('.nav-link');
if (!trigger) return;
trigger.addEventListener('click', function (e) {
if (window.innerWidth <= 768) {
e.preventDefault();
dd.classList.toggle('open');
}
});
});
/* ---- Active nav link highlight ---- */
var currentPage = window.location.pathname.split('/').pop() || 'index.html';
document.querySelectorAll('.nav-links a, .doc-nav-item').forEach(function (link) {
var href = link.getAttribute('href');
if (!href) return;
var linkPage = href.split('/').pop().split('#')[0] || 'index.html';
if (linkPage === currentPage) {
link.classList.add('active');
}
});
/* ---- Smooth anchor scroll ---- */
document.querySelectorAll('a[href^="#"]').forEach(function (a) {
a.addEventListener('click', function (e) {
var id = a.getAttribute('href').substring(1);
var target = document.getElementById(id);
if (target) {
e.preventDefault();
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
history.pushState(null, '', '#' + id);
}
});
});
})();
+160
View File
@@ -0,0 +1,160 @@
/* ============================================================
ChronoSeal Website — diagrams.js
Generates SVG architecture & protocol flow diagrams inline
============================================================ */
var ChronoDiagrams = (function () {
'use strict';
function drawArchitecture(containerId) {
var el = document.getElementById(containerId);
if (!el) return;
var svg = '<svg viewBox="0 0 760 420" fill="none" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;max-width:760px">';
/* Background */
svg += '<rect width="760" height="420" rx="12" fill="#131620"/>';
/* Browser box */
svg += '<rect x="40" y="30" width="280" height="170" rx="8" fill="#1e2230" stroke="#2a2f40" stroke-width="1.5"/>';
svg += '<text x="180" y="55" fill="#b0b2b8" font-size="11" font-weight="700" text-anchor="middle" font-family="Inter,sans-serif">BROWSER</text>';
svg += '<rect x="60" y="70" width="110" height="36" rx="5" fill="#252a3a" stroke="#2a2f40"/>';
svg += '<text x="115" y="93" fill="#e1e1e4" font-size="10" text-anchor="middle" font-family="Inter,sans-serif">WASM Runtime</text>';
svg += '<rect x="190" y="70" width="110" height="36" rx="5" fill="#252a3a" stroke="#2a2f40"/>';
svg += '<text x="245" y="93" fill="#e1e1e4" font-size="10" text-anchor="middle" font-family="Inter,sans-serif">heartbeat.js</text>';
svg += '<rect x="60" y="120" width="110" height="36" rx="5" fill="#252a3a" stroke="#2a2f40"/>';
svg += '<text x="115" y="143" fill="#e1e1e4" font-size="10" text-anchor="middle" font-family="Inter,sans-serif">Ed25519 Keys</text>';
svg += '<rect x="190" y="120" width="110" height="36" rx="5" fill="#252a3a" stroke="#2a2f40"/>';
svg += '<text x="245" y="143" fill="#e1e1e4" font-size="10" text-anchor="middle" font-family="Inter,sans-serif">Gene Engine</text>';
svg += '<text x="180" y="185" fill="#6b6f7a" font-size="9" text-anchor="middle" font-family="Inter,sans-serif">Entropy · Signing · VM · Mutation</text>';
/* Arrow: Browser → Server */
svg += '<line x1="320" y1="115" x2="430" y2="115" stroke="#7b7e85" stroke-width="1.5" stroke-dasharray="6 3"/>';
svg += '<polygon points="428,110 438,115 428,120" fill="#7b7e85"/>';
svg += '<text x="375" y="105" fill="#6b6f7a" font-size="8" text-anchor="middle" font-family="Inter,sans-serif">POST /hb</text>';
svg += '<text x="375" y="135" fill="#6b6f7a" font-size="8" text-anchor="middle" font-family="Inter,sans-serif">POST /init</text>';
/* Server box */
svg += '<rect x="440" y="30" width="280" height="170" rx="8" fill="#1e2230" stroke="#2a2f40" stroke-width="1.5"/>';
svg += '<text x="580" y="55" fill="#b0b2b8" font-size="11" font-weight="700" text-anchor="middle" font-family="Inter,sans-serif">SERVER (chronoseal)</text>';
svg += '<rect x="460" y="70" width="110" height="36" rx="5" fill="#252a3a" stroke="#2a2f40"/>';
svg += '<text x="515" y="93" fill="#e1e1e4" font-size="10" text-anchor="middle" font-family="Inter,sans-serif">Axum Router</text>';
svg += '<rect x="590" y="70" width="110" height="36" rx="5" fill="#252a3a" stroke="#2a2f40"/>';
svg += '<text x="645" y="93" fill="#e1e1e4" font-size="10" text-anchor="middle" font-family="Inter,sans-serif">Rate Limiter</text>';
svg += '<rect x="460" y="120" width="110" height="36" rx="5" fill="#252a3a" stroke="#2a2f40"/>';
svg += '<text x="515" y="143" fill="#e1e1e4" font-size="10" text-anchor="middle" font-family="Inter,sans-serif">Verifier</text>';
svg += '<rect x="590" y="120" width="110" height="36" rx="5" fill="#252a3a" stroke="#2a2f40"/>';
svg += '<text x="645" y="143" fill="#e1e1e4" font-size="10" text-anchor="middle" font-family="Inter,sans-serif">Gene Engine</text>';
svg += '<text x="580" y="185" fill="#6b6f7a" font-size="9" text-anchor="middle" font-family="Inter,sans-serif">Verify · Advance · Trust · CAS</text>';
/* Shared box (bottom center) */
svg += '<rect x="230" y="240" width="300" height="60" rx="8" fill="#1e2230" stroke="#b0b2b8" stroke-width="1" stroke-dasharray="4 3"/>';
svg += '<text x="380" y="266" fill="#b0b2b8" font-size="11" font-weight="700" text-anchor="middle" font-family="Inter,sans-serif">shared crate</text>';
svg += '<text x="380" y="284" fill="#6b6f7a" font-size="9" text-anchor="middle" font-family="Inter,sans-serif">Protocol · Hashing · Gene · VM · Constants</text>';
/* Arrows to shared */
svg += '<line x1="180" y1="200" x2="310" y2="244" stroke="#7b7e85" stroke-width="1" stroke-dasharray="4 3"/>';
svg += '<line x1="580" y1="200" x2="450" y2="244" stroke="#7b7e85" stroke-width="1" stroke-dasharray="4 3"/>';
/* Storage box */
svg += '<rect x="440" y="340" width="280" height="55" rx="8" fill="#1e2230" stroke="#2a2f40" stroke-width="1.5"/>';
svg += '<text x="580" y="365" fill="#b0b2b8" font-size="11" font-weight="700" text-anchor="middle" font-family="Inter,sans-serif">STORAGE</text>';
svg += '<text x="580" y="382" fill="#6b6f7a" font-size="9" text-anchor="middle" font-family="Inter,sans-serif">SQLite In-Memory · SQLite Disk · Valkey</text>';
/* Server → Storage arrow */
svg += '<line x1="580" y1="200" x2="580" y2="340" stroke="#7b7e85" stroke-width="1.5" stroke-dasharray="6 3"/>';
svg += '<polygon points="575,338 580,348 585,338" fill="#7b7e85"/>';
/* CLI box */
svg += '<rect x="40" y="340" width="170" height="55" rx="8" fill="#1e2230" stroke="#2a2f40" stroke-width="1.5"/>';
svg += '<text x="125" y="365" fill="#b0b2b8" font-size="11" font-weight="700" text-anchor="middle" font-family="Inter,sans-serif">CLI</text>';
svg += '<text x="125" y="382" fill="#6b6f7a" font-size="9" text-anchor="middle" font-family="Inter,sans-serif">status · health · metrics · stats</text>';
svg += '</svg>';
el.innerHTML = svg;
}
function drawProtocolFlow(containerId) {
var el = document.getElementById(containerId);
if (!el) return;
var svg = '<svg viewBox="0 0 600 520" fill="none" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;max-width:600px">';
svg += '<rect width="600" height="520" rx="12" fill="#131620"/>';
/* Columns */
svg += '<text x="150" y="30" fill="#b0b2b8" font-size="12" font-weight="700" text-anchor="middle" font-family="Inter,sans-serif">Browser</text>';
svg += '<text x="450" y="30" fill="#b0b2b8" font-size="12" font-weight="700" text-anchor="middle" font-family="Inter,sans-serif">Server</text>';
/* Lifelines */
svg += '<line x1="150" y1="44" x2="150" y2="500" stroke="#2a2f40" stroke-width="1.5"/>';
svg += '<line x1="450" y1="44" x2="450" y2="500" stroke="#2a2f40" stroke-width="1.5"/>';
var y = 70;
var arrows = [
{ from: 150, to: 450, label: 'Generate Ed25519 keypair', note: '', dir: 'self' },
{ from: 150, to: 450, label: 'POST /init { public_key }', note: '', dir: 'right' },
{ from: 450, to: 150, label: '{ session_id, salt, opcodes, gene_size, mutation_order }', note: '', dir: 'left' },
{ from: 150, to: 450, label: 'Execute VM program', note: '', dir: 'self' },
{ from: 150, to: 450, label: 'Collect entropy + sign payload', note: '', dir: 'self' },
{ from: 150, to: 450, label: 'Preview gene commitment', note: '', dir: 'self' },
{ from: 150, to: 450, label: 'POST /hb { session_id, hash, signature, gene_commitment, … }', note: '', dir: 'right' },
{ from: 450, to: 150, label: 'Verify chain + signature + gene + trust', note: '', dir: 'selfr' },
{ from: 450, to: 150, label: '{ next_salt, next_mutation_step, next_mutation_order }', note: 'accepted', dir: 'left' },
{ from: 450, to: 150, label: '{ status: "ok" }', note: 'rejected (silent)', dir: 'left' },
];
for (var i = 0; i < arrows.length; i++) {
var a = arrows[i];
if (a.dir === 'right') {
svg += '<line x1="155" y1="' + y + '" x2="445" y2="' + y + '" stroke="#7b7e85" stroke-width="1.2"/>';
svg += '<polygon points="443,' + (y - 4) + ' 450,' + y + ' 443,' + (y + 4) + '" fill="#7b7e85"/>';
svg += '<text x="300" y="' + (y - 8) + '" fill="#e1e1e4" font-size="8.5" text-anchor="middle" font-family="Inter,sans-serif">' + a.label + '</text>';
} else if (a.dir === 'left') {
svg += '<line x1="445" y1="' + y + '" x2="155" y2="' + y + '" stroke="#7b7e85" stroke-width="1.2"/>';
svg += '<polygon points="157,' + (y - 4) + ' 150,' + y + ' 157,' + (y + 4) + '" fill="#7b7e85"/>';
svg += '<text x="300" y="' + (y - 8) + '" fill="#e1e1e4" font-size="8.5" text-anchor="middle" font-family="Inter,sans-serif">' + a.label + '</text>';
if (a.note) {
svg += '<text x="300" y="' + (y + 14) + '" fill="#6b6f7a" font-size="8" text-anchor="middle" font-style="italic" font-family="Inter,sans-serif">' + a.note + '</text>';
y += 8;
}
} else if (a.dir === 'self') {
svg += '<rect x="60" y="' + (y - 12) + '" width="180" height="22" rx="4" fill="#252a3a" stroke="#2a2f40"/>';
svg += '<text x="150" y="' + (y + 3) + '" fill="#9a9da6" font-size="8.5" text-anchor="middle" font-family="Inter,sans-serif">' + a.label + '</text>';
} else if (a.dir === 'selfr') {
svg += '<rect x="360" y="' + (y - 12) + '" width="180" height="22" rx="4" fill="#252a3a" stroke="#2a2f40"/>';
svg += '<text x="450" y="' + (y + 3) + '" fill="#9a9da6" font-size="8.5" text-anchor="middle" font-family="Inter,sans-serif">' + a.label + '</text>';
}
y += 44;
}
svg += '</svg>';
el.innerHTML = svg;
}
/* ---- Auto-init ---- */
function init() {
drawArchitecture('diagram-architecture');
drawProtocolFlow('diagram-protocol');
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
return {
drawArchitecture: drawArchitecture,
drawProtocolFlow: drawProtocolFlow
};
})();
+41
View File
@@ -0,0 +1,41 @@
/* ============================================================
ChronoSeal Website — pwa.js
Progressive Web App: service worker registration + install
============================================================ */
(function () {
'use strict';
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('/sw.js').then(function (reg) {
/* Update found — silent refresh */
reg.addEventListener('updatefound', function () {
var worker = reg.installing;
if (!worker) return;
worker.addEventListener('statechange', function () {
if (worker.state === 'activated' && navigator.serviceWorker.controller) {
/* New version available — user can refresh */
}
});
});
}).catch(function () {
/* SW registration failed — app still works */
});
});
}
/* ---- Installable PWA banner (A2HS) ---- */
var deferredPrompt = null;
window.addEventListener('beforeinstallprompt', function (e) {
e.preventDefault();
deferredPrompt = e;
/* Could show a custom install banner here */
});
window.addEventListener('appinstalled', function () {
deferredPrompt = null;
});
})();
+144
View File
@@ -0,0 +1,144 @@
/* ============================================================
ChronoSeal Website — search.js
Client-side full-text search across all pages
============================================================ */
var ChronoSearch = (function () {
'use strict';
/* ---- Search index ---- */
var pages = [
{ title: 'Home', url: 'index.html', desc: 'ChronoSeal overview, features, and quick start', keywords: 'home overview features quick start install' },
{ title: 'Architecture', url: 'architecture.html', desc: 'System architecture, crate layout, and data flow', keywords: 'architecture crates workspace wasm shared server' },
{ title: 'Protocol', url: 'protocol.html', desc: 'Heartbeat protocol, hash chain, and mutation engine', keywords: 'protocol heartbeat hash chain blake3 ed25519 mutation gene' },
{ title: 'API Reference', url: 'api.html', desc: 'HTTP endpoints: /init, /hb, /health, /metrics, /stats', keywords: 'api http post init heartbeat health metrics stats json' },
{ title: 'Deployment', url: 'deployment.html', desc: 'Installation, systemd, Docker, nginx reverse proxy', keywords: 'deploy install systemd docker nginx proxy production' },
{ title: 'Threat Model', url: 'threat-model.html', desc: 'Security threat model and defense boundaries', keywords: 'threat model security attack replay automation defense' },
{ title: 'Performance', url: 'performance.html', desc: 'Performance tuning, benchmarks, and optimization', keywords: 'performance tuning benchmark latency throughput' },
{ title: 'Philosophy', url: 'philosophy.html', desc: 'Design philosophy and engineering priorities', keywords: 'philosophy design unix privacy operator control' },
{ title: 'Privacy Policy', url: 'privacy.html', desc: 'Data handling, storage, and privacy commitments', keywords: 'privacy policy data collection storage session' },
{ title: 'Security', url: 'security.html', desc: 'Security assumptions, hardening, and response headers', keywords: 'security assumptions headers hardening csp' },
{ title: 'Operations', url: 'operations.html', desc: 'Monitoring, health checks, metrics, and logging', keywords: 'operations health status metrics stats logging monitor' },
{ title: 'Testing', url: 'testing.html', desc: 'Test suite, fuzzing, and validation coverage', keywords: 'testing tests cargo fuzz validation fingerprint' },
{ title: 'Comparison', url: 'comparison.html', desc: 'ChronoSeal vs commercial anti-bot solutions', keywords: 'comparison cloudflare akamai recaptcha datadome kasada' },
];
var overlay = null;
var input = null;
var results = null;
function init() {
overlay = document.querySelector('.search-overlay');
input = document.querySelector('.search-input');
results = document.querySelector('.search-results');
if (!overlay || !input || !results) return;
input.addEventListener('input', debounce(onInput, 150));
overlay.addEventListener('click', function (e) {
if (e.target === overlay) close();
});
// Keyboard nav inside results
input.addEventListener('keydown', function (e) {
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
e.preventDefault();
navigateResults(e.key === 'ArrowDown' ? 1 : -1);
}
if (e.key === 'Enter') {
var sel = results.querySelector('.search-result.selected');
if (sel) { window.location.href = sel.getAttribute('href'); close(); }
}
});
}
function open() {
if (!overlay) init();
if (!overlay) return;
overlay.classList.add('open');
input.value = '';
results.innerHTML = renderHints();
setTimeout(function () { input.focus(); }, 100);
}
function close() {
if (overlay) overlay.classList.remove('open');
}
function onInput() {
var q = input.value.trim().toLowerCase();
if (!q) { results.innerHTML = renderHints(); return; }
var matches = [];
for (var i = 0; i < pages.length; i++) {
var p = pages[i];
var hay = (p.title + ' ' + p.desc + ' ' + p.keywords).toLowerCase();
if (hay.indexOf(q) !== -1) {
matches.push(p);
}
}
if (matches.length === 0) {
results.innerHTML = '<div class="search-empty">No results for &ldquo;' + escHtml(q) + '&rdquo;</div>';
return;
}
var html = '';
for (var j = 0; j < matches.length; j++) {
var m = matches[j];
html += '<a class="search-result' + (j === 0 ? ' selected' : '') + '" href="' + m.url + '">';
html += '<div class="search-result-title">' + highlightMatch(m.title, q) + '</div>';
html += '<div class="search-result-desc">' + highlightMatch(m.desc, q) + '</div>';
html += '</a>';
}
results.innerHTML = html;
}
function navigateResults(dir) {
var items = results.querySelectorAll('.search-result');
if (!items.length) return;
var idx = -1;
for (var i = 0; i < items.length; i++) {
if (items[i].classList.contains('selected')) { idx = i; break; }
}
if (idx >= 0) items[idx].classList.remove('selected');
idx = Math.max(0, Math.min(items.length - 1, idx + dir));
items[idx].classList.add('selected');
items[idx].scrollIntoView({ block: 'nearest' });
}
function renderHints() {
return '<div class="search-empty">Type to search documentation&hellip;<br><span style="font-size:.78rem;color:var(--text-muted)">↑↓ Navigate &middot; ↵ Open &middot; Esc Close</span></div>';
}
function highlightMatch(text, q) {
var idx = text.toLowerCase().indexOf(q);
if (idx === -1) return escHtml(text);
return escHtml(text.substring(0, idx)) +
'<mark style="background:rgba(176,178,184,.2);color:var(--text-primary);border-radius:2px;padding:0 2px">' +
escHtml(text.substring(idx, idx + q.length)) + '</mark>' +
escHtml(text.substring(idx + q.length));
}
function escHtml(s) {
var div = document.createElement('div');
div.appendChild(document.createTextNode(s));
return div.innerHTML;
}
function debounce(fn, ms) {
var t;
return function () {
clearTimeout(t);
t = setTimeout(fn, ms);
};
}
/* ---- Auto-init ---- */
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
return { open: open, close: close };
})();