403 lines
9.9 KiB
HTML
403 lines
9.9 KiB
HTML
|
|
<!DOCTYPE html>
|
||
|
|
<html lang="en">
|
||
|
|
<head>
|
||
|
|
<meta charset="UTF-8">
|
||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
|
|
<title>stratumiops — Ontology + Reflection System</title>
|
||
|
|
<style>
|
||
|
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||
|
|
|
||
|
|
:root {
|
||
|
|
--bg: #0f172a;
|
||
|
|
--surface: #1e293b;
|
||
|
|
--surface-deep: #0f172a;
|
||
|
|
--border: #334155;
|
||
|
|
--text-primary: #f1f5f9;
|
||
|
|
--text-secondary: #94a3b8;
|
||
|
|
--text-muted: #475569;
|
||
|
|
--accent-blue: #3b82f6;
|
||
|
|
--accent-amber: #fbbf24;
|
||
|
|
--accent-green: #34d399;
|
||
|
|
--accent-purple: #a78bfa;
|
||
|
|
--font: ui-monospace, 'JetBrains Mono', 'Fira Code', monospace;
|
||
|
|
}
|
||
|
|
|
||
|
|
body {
|
||
|
|
background: var(--bg);
|
||
|
|
color: var(--text-primary);
|
||
|
|
font-family: var(--font);
|
||
|
|
min-height: 100vh;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ── PRESENTATION MODE ── */
|
||
|
|
#presentation {
|
||
|
|
display: none;
|
||
|
|
position: fixed;
|
||
|
|
inset: 0;
|
||
|
|
background: #000;
|
||
|
|
z-index: 100;
|
||
|
|
flex-direction: column;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
}
|
||
|
|
|
||
|
|
#presentation.active {
|
||
|
|
display: flex;
|
||
|
|
}
|
||
|
|
|
||
|
|
#slide-container {
|
||
|
|
width: 100%;
|
||
|
|
max-width: min(100vw, calc(100vh * 16 / 9));
|
||
|
|
aspect-ratio: 16 / 9;
|
||
|
|
position: relative;
|
||
|
|
}
|
||
|
|
|
||
|
|
#slide-container img {
|
||
|
|
width: 100%;
|
||
|
|
height: 100%;
|
||
|
|
object-fit: contain;
|
||
|
|
display: block;
|
||
|
|
}
|
||
|
|
|
||
|
|
#presentation-controls {
|
||
|
|
position: fixed;
|
||
|
|
bottom: 0;
|
||
|
|
left: 0;
|
||
|
|
right: 0;
|
||
|
|
height: 52px;
|
||
|
|
background: rgba(15, 23, 42, 0.92);
|
||
|
|
border-top: 1px solid var(--border);
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
gap: 24px;
|
||
|
|
backdrop-filter: blur(8px);
|
||
|
|
}
|
||
|
|
|
||
|
|
#presentation-controls button {
|
||
|
|
background: var(--surface);
|
||
|
|
border: 1px solid var(--border);
|
||
|
|
color: var(--text-primary);
|
||
|
|
font-family: var(--font);
|
||
|
|
font-size: 12px;
|
||
|
|
padding: 6px 16px;
|
||
|
|
border-radius: 4px;
|
||
|
|
cursor: pointer;
|
||
|
|
letter-spacing: 1px;
|
||
|
|
transition: background 0.15s, border-color 0.15s;
|
||
|
|
}
|
||
|
|
|
||
|
|
#presentation-controls button:hover {
|
||
|
|
background: #334155;
|
||
|
|
border-color: var(--accent-blue);
|
||
|
|
}
|
||
|
|
|
||
|
|
#presentation-controls button:disabled {
|
||
|
|
opacity: 0.3;
|
||
|
|
cursor: not-allowed;
|
||
|
|
}
|
||
|
|
|
||
|
|
#slide-counter {
|
||
|
|
font-size: 12px;
|
||
|
|
color: var(--text-muted);
|
||
|
|
min-width: 60px;
|
||
|
|
text-align: center;
|
||
|
|
}
|
||
|
|
|
||
|
|
#exit-presentation {
|
||
|
|
position: fixed;
|
||
|
|
top: 16px;
|
||
|
|
right: 16px;
|
||
|
|
background: rgba(15, 23, 42, 0.8);
|
||
|
|
border: 1px solid var(--border);
|
||
|
|
color: var(--text-secondary);
|
||
|
|
font-family: var(--font);
|
||
|
|
font-size: 11px;
|
||
|
|
padding: 6px 12px;
|
||
|
|
border-radius: 4px;
|
||
|
|
cursor: pointer;
|
||
|
|
z-index: 200;
|
||
|
|
letter-spacing: 1px;
|
||
|
|
}
|
||
|
|
|
||
|
|
#exit-presentation:hover {
|
||
|
|
color: var(--text-primary);
|
||
|
|
border-color: var(--accent-blue);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ── GALLERY MODE ── */
|
||
|
|
#gallery {
|
||
|
|
min-height: 100vh;
|
||
|
|
}
|
||
|
|
|
||
|
|
header {
|
||
|
|
padding: 32px 48px 24px;
|
||
|
|
border-bottom: 1px solid var(--border);
|
||
|
|
display: flex;
|
||
|
|
align-items: baseline;
|
||
|
|
gap: 24px;
|
||
|
|
}
|
||
|
|
|
||
|
|
header h1 {
|
||
|
|
font-size: 18px;
|
||
|
|
font-weight: 700;
|
||
|
|
color: var(--text-primary);
|
||
|
|
letter-spacing: -0.5px;
|
||
|
|
}
|
||
|
|
|
||
|
|
header span {
|
||
|
|
font-size: 12px;
|
||
|
|
color: var(--text-muted);
|
||
|
|
letter-spacing: 2px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.start-btn {
|
||
|
|
margin-left: auto;
|
||
|
|
background: var(--accent-blue);
|
||
|
|
border: none;
|
||
|
|
color: #fff;
|
||
|
|
font-family: var(--font);
|
||
|
|
font-size: 12px;
|
||
|
|
padding: 8px 20px;
|
||
|
|
border-radius: 4px;
|
||
|
|
cursor: pointer;
|
||
|
|
letter-spacing: 1px;
|
||
|
|
font-weight: 600;
|
||
|
|
}
|
||
|
|
|
||
|
|
.start-btn:hover {
|
||
|
|
background: #2563eb;
|
||
|
|
}
|
||
|
|
|
||
|
|
.slides-grid {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: repeat(auto-fill, minmax(380px, 1fr));
|
||
|
|
gap: 24px;
|
||
|
|
padding: 32px 48px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.slide-card {
|
||
|
|
cursor: pointer;
|
||
|
|
border: 1px solid var(--border);
|
||
|
|
border-radius: 8px;
|
||
|
|
overflow: hidden;
|
||
|
|
background: var(--surface);
|
||
|
|
transition: border-color 0.15s, transform 0.15s, box-shadow 0.15s;
|
||
|
|
}
|
||
|
|
|
||
|
|
.slide-card:hover {
|
||
|
|
border-color: var(--accent-blue);
|
||
|
|
transform: translateY(-2px);
|
||
|
|
box-shadow: 0 8px 24px rgba(59, 130, 246, 0.15);
|
||
|
|
}
|
||
|
|
|
||
|
|
.slide-card img {
|
||
|
|
width: 100%;
|
||
|
|
aspect-ratio: 16 / 9;
|
||
|
|
display: block;
|
||
|
|
object-fit: cover;
|
||
|
|
}
|
||
|
|
|
||
|
|
.slide-card-meta {
|
||
|
|
padding: 10px 14px;
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: space-between;
|
||
|
|
border-top: 1px solid var(--border);
|
||
|
|
}
|
||
|
|
|
||
|
|
.slide-number {
|
||
|
|
font-size: 11px;
|
||
|
|
color: var(--text-muted);
|
||
|
|
letter-spacing: 1px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.slide-status {
|
||
|
|
font-size: 10px;
|
||
|
|
letter-spacing: 1px;
|
||
|
|
padding: 2px 8px;
|
||
|
|
border-radius: 3px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.slide-status.full {
|
||
|
|
background: rgba(52, 211, 153, 0.12);
|
||
|
|
color: var(--accent-green);
|
||
|
|
border: 1px solid rgba(52, 211, 153, 0.3);
|
||
|
|
}
|
||
|
|
|
||
|
|
.slide-status.stub {
|
||
|
|
background: rgba(71, 85, 105, 0.2);
|
||
|
|
color: var(--text-muted);
|
||
|
|
border: 1px solid var(--border);
|
||
|
|
}
|
||
|
|
|
||
|
|
footer {
|
||
|
|
padding: 24px 48px;
|
||
|
|
border-top: 1px solid var(--border);
|
||
|
|
display: flex;
|
||
|
|
justify-content: space-between;
|
||
|
|
align-items: center;
|
||
|
|
}
|
||
|
|
|
||
|
|
footer span {
|
||
|
|
font-size: 11px;
|
||
|
|
color: var(--text-muted);
|
||
|
|
letter-spacing: 2px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.key-hint {
|
||
|
|
font-size: 11px;
|
||
|
|
color: var(--text-muted);
|
||
|
|
}
|
||
|
|
|
||
|
|
.key-hint kbd {
|
||
|
|
background: var(--surface);
|
||
|
|
border: 1px solid var(--border);
|
||
|
|
border-radius: 3px;
|
||
|
|
padding: 1px 6px;
|
||
|
|
font-family: var(--font);
|
||
|
|
font-size: 10px;
|
||
|
|
}
|
||
|
|
</style>
|
||
|
|
</head>
|
||
|
|
<body>
|
||
|
|
|
||
|
|
<!-- PRESENTATION MODE -->
|
||
|
|
<div id="presentation">
|
||
|
|
<button id="exit-presentation" onclick="exitPresentation()">ESC · EXIT</button>
|
||
|
|
<div id="slide-container">
|
||
|
|
<img id="current-slide" src="" alt="Slide">
|
||
|
|
</div>
|
||
|
|
<div id="presentation-controls">
|
||
|
|
<button id="btn-prev" onclick="prevSlide()">← PREV</button>
|
||
|
|
<span id="slide-counter">01 / 14</span>
|
||
|
|
<button id="btn-next" onclick="nextSlide()">NEXT →</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- GALLERY MODE -->
|
||
|
|
<div id="gallery">
|
||
|
|
<header>
|
||
|
|
<h1>stratumiops</h1>
|
||
|
|
<span>ONTOLOGY + REFLECTION SYSTEM</span>
|
||
|
|
<button class="start-btn" onclick="startPresentation(1)">PRESENT →</button>
|
||
|
|
</header>
|
||
|
|
|
||
|
|
<div class="slides-grid" id="slides-grid"></div>
|
||
|
|
|
||
|
|
<footer>
|
||
|
|
<span>STRATUMIOPS · 14 SLIDES</span>
|
||
|
|
<span class="key-hint">
|
||
|
|
<kbd>←</kbd> <kbd>→</kbd> navigate · <kbd>Esc</kbd> exit · click to open
|
||
|
|
</span>
|
||
|
|
</footer>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<script>
|
||
|
|
const TOTAL = 14;
|
||
|
|
const FULL_SLIDES = [1, 2, 3, 4, 5];
|
||
|
|
|
||
|
|
const TITLES = [
|
||
|
|
"Problems We Are Solving",
|
||
|
|
"Yin / Yang — Truth and Coexistence",
|
||
|
|
"Ingredient List — The Stack",
|
||
|
|
"Nickel — What and Why",
|
||
|
|
"Nushell — What and Why",
|
||
|
|
"DAGs and FSMs — Acyclic Graphs",
|
||
|
|
"Operational Ontology — Why and How",
|
||
|
|
"Reflection — Definitions",
|
||
|
|
"ADRs — Making Decisions Alive",
|
||
|
|
"Implementation — Parts and Definitions",
|
||
|
|
"Mechanics and Workflow — Use Cases",
|
||
|
|
"Integration in Projects",
|
||
|
|
"Integration with Claude Code",
|
||
|
|
"Concurrent Use",
|
||
|
|
];
|
||
|
|
|
||
|
|
let currentSlide = 1;
|
||
|
|
|
||
|
|
function padNum(n) {
|
||
|
|
return String(n).padStart(2, '0');
|
||
|
|
}
|
||
|
|
|
||
|
|
function slideSrc(n) {
|
||
|
|
return `slide-${padNum(n)}.svg`;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Build gallery
|
||
|
|
const grid = document.getElementById('slides-grid');
|
||
|
|
for (let i = 1; i <= TOTAL; i++) {
|
||
|
|
const isFull = FULL_SLIDES.includes(i);
|
||
|
|
const card = document.createElement('div');
|
||
|
|
card.className = 'slide-card';
|
||
|
|
card.dataset.slide = i;
|
||
|
|
card.onclick = () => startPresentation(i);
|
||
|
|
card.innerHTML = `
|
||
|
|
<img src="${slideSrc(i)}" alt="Slide ${padNum(i)}" loading="lazy">
|
||
|
|
<div class="slide-card-meta">
|
||
|
|
<span class="slide-number">${padNum(i)} / ${padNum(TOTAL)} · ${TITLES[i - 1]}</span>
|
||
|
|
<span class="slide-status ${isFull ? 'full' : 'stub'}">${isFull ? 'FULL' : 'STUB'}</span>
|
||
|
|
</div>
|
||
|
|
`;
|
||
|
|
grid.appendChild(card);
|
||
|
|
}
|
||
|
|
|
||
|
|
function startPresentation(n) {
|
||
|
|
currentSlide = n || 1;
|
||
|
|
document.getElementById('presentation').classList.add('active');
|
||
|
|
document.getElementById('gallery').style.display = 'none';
|
||
|
|
updateSlide();
|
||
|
|
document.addEventListener('keydown', handleKey);
|
||
|
|
}
|
||
|
|
|
||
|
|
function exitPresentation() {
|
||
|
|
document.getElementById('presentation').classList.remove('active');
|
||
|
|
document.getElementById('gallery').style.display = '';
|
||
|
|
document.removeEventListener('keydown', handleKey);
|
||
|
|
}
|
||
|
|
|
||
|
|
function updateSlide() {
|
||
|
|
const img = document.getElementById('current-slide');
|
||
|
|
img.src = slideSrc(currentSlide);
|
||
|
|
img.alt = `Slide ${currentSlide}: ${TITLES[currentSlide - 1]}`;
|
||
|
|
document.getElementById('slide-counter').textContent = `${padNum(currentSlide)} / ${padNum(TOTAL)}`;
|
||
|
|
document.getElementById('btn-prev').disabled = currentSlide <= 1;
|
||
|
|
document.getElementById('btn-next').disabled = currentSlide >= TOTAL;
|
||
|
|
}
|
||
|
|
|
||
|
|
function prevSlide() {
|
||
|
|
if (currentSlide > 1) { currentSlide--; updateSlide(); }
|
||
|
|
}
|
||
|
|
|
||
|
|
function nextSlide() {
|
||
|
|
if (currentSlide < TOTAL) { currentSlide++; updateSlide(); }
|
||
|
|
}
|
||
|
|
|
||
|
|
function handleKey(e) {
|
||
|
|
switch (e.key) {
|
||
|
|
case 'ArrowRight':
|
||
|
|
case 'ArrowDown':
|
||
|
|
case ' ':
|
||
|
|
e.preventDefault();
|
||
|
|
nextSlide();
|
||
|
|
break;
|
||
|
|
case 'ArrowLeft':
|
||
|
|
case 'ArrowUp':
|
||
|
|
e.preventDefault();
|
||
|
|
prevSlide();
|
||
|
|
break;
|
||
|
|
case 'Escape':
|
||
|
|
exitPresentation();
|
||
|
|
break;
|
||
|
|
case 'Home':
|
||
|
|
currentSlide = 1; updateSlide();
|
||
|
|
break;
|
||
|
|
case 'End':
|
||
|
|
currentSlide = TOTAL; updateSlide();
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
</body>
|
||
|
|
</html>
|