---
import BaseLayout from '../layouts/BaseLayout.astro';
import '../styles/css/sections/hero.css';
import '../styles/css/sections/features.css';
import '../styles/css/sections/architecture.css';
import '../styles/css/sections/code-window.css';
---
<BaseLayout>
<section class="hero varve-layer layer-1">
<div id="hero-canvas"></div>
<div class="container hero-content">
<img src="/logo.svg" alt="VarveDB Logo" class="hero-logo" />
<h1>The Embedded <br/><span class="highlight">Event Store</span></h1>
<p class="tagline">Zero-copy event storage with sub-microsecond reads and 1M+ events/sec batch writes.</p>
<div class="cta-group">
<a href="/docs/quick_start" class="btn btn-primary">Get Started</a>
<a href="/docs/introduction" class="btn btn-secondary">Read the Docs</a>
</div>
<div class="install-cmd">
<span class="prefix">$</span> cargo add varvedb
<button class="copy-btn" aria-label="Copy command">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
</button>
</div>
</div>
</section>
<section id="features" class="features varve-layer layer-2">
<div class="container">
<h2>Built for Speed and Reliability</h2>
<div class="features-grid">
<div class="feature-card fade-in-section">
<div class="feature-icon">
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" /></svg>
</div>
<h3>Zero-Copy Reads</h3>
<p>Leverages <a href="https://rkyv.org/" class="tech-link">rkyv</a> to map data directly from disk. No deserialization means reads complete in nanoseconds.</p>
</div>
<div class="feature-card fade-in-section">
<div class="feature-icon">
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" /></svg>
</div>
<h3>Batch Writes</h3>
<p>Achieve 700x throughput gains by batching events. Single transaction overhead amortized across thousands of events.</p>
</div>
<div class="feature-card fade-in-section">
<div class="feature-icon">
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" /></svg>
</div>
<h3>Append-Only Log</h3>
<p>Immutable event stream ensures data integrity and simplifies replication. Perfect for Event Sourcing and CQRS.</p>
</div>
</div>
</div>
</section>
<section id="architecture" class="architecture varve-layer layer-3">
<div class="container">
<h2>Architecture</h2>
<p class="section-desc">Memory-mapped storage for maximum throughput. Built on LMDB for ACID guarantees.</p>
<div class="arch-container">
<!-- Diagram Side -->
<div class="arch-diagram">
<div class="data-packet packet-write"></div>
<div class="data-packet packet-read"></div>
<div class="arch-box user" data-id="user">User Application</div>
<div class="arch-flow">
<span class="arch-icon">⬇</span>
<span>Zero-Copy Read / Batch Append</span>
</div>
<div class="arch-box varvedb" data-id="varvedb">
<div class="arch-title">VarveDB Engine</div>
<div class="arch-inner">
<div class="arch-component" data-id="stream">Stream Handler</div>
<div class="arch-component" data-id="indexer">Index Manager</div>
<div class="arch-component" data-id="cache">Page Cache</div>
</div>
<div class="arch-flow internal">
<span class="arch-icon">⬇</span>
<span>mmap / fsync</span>
</div>
<div class="arch-box storage" data-id="storage">LMDB / Disk</div>
</div>
</div>
<!-- Code Side -->
<div class="code-window fade-in-section">
<div class="code-header">
<div class="code-dots"><span></span><span></span><span></span></div>
<div class="code-title">src/main.rs</div>
</div>
<pre is:raw><code><span class="keyword">use</span> varvedb::{Varve, StreamId};
<span class="keyword">fn</span> <span class="function">main</span>() -> <span class="type">Result</span><(), <span class="type">Error</span>> {
<span class="code-line" data-related-id="varvedb"> <span class="comment">// Initialize the event store</span></span>
<span class="code-line" data-related-id="varvedb"> <span class="keyword">let</span> <span class="keyword">mut</span> varve = <span class="type">Varve</span>::<span class="function">new</span>(<span class="string">"./data"</span>)?;</span>
<span class="code-line" data-related-id="stream"> <span class="comment">// Create a typed stream</span></span>
<span class="code-line" data-related-id="stream"> <span class="keyword">let</span> <span class="keyword">mut</span> stream = varve.<span class="function">stream</span>::<<span class="type">Event</span>, <span class="number">256</span>>(<span class="string">"orders"</span>)?;</span>
<span class="code-line" data-related-id="stream"> <span class="comment">// Append events (zero-copy on read)</span></span>
<span class="code-line" data-related-id="stream"> <span class="keyword">let</span> (seq, _) = stream.<span class="function">append</span>(<span class="type">StreamId</span>(<span class="number">1</span>), &event)?;</span>
<span class="code-line" data-related-id="indexer"> <span class="comment">// Read back instantly</span></span>
<span class="code-line" data-related-id="indexer"> <span class="keyword">let</span> bytes = stream.<span class="function">get_bytes</span>(<span class="type">StreamId</span>(<span class="number">1</span>), seq)?;</span>
<span class="keyword">Ok</span>(())
}</code></pre>
</div>
</div>
</div>
</section>
</BaseLayout>
<script>
import { initHero3D } from '../js/hero-3d.js';
// Initialize 3D Hero
initHero3D();
// Simple intersection observer for fade-in animations
const observerOptions = {
root: null,
rootMargin: '0px',
threshold: 0.1
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
}
});
}, observerOptions);
document.querySelectorAll('.fade-in-section').forEach(el => observer.observe(el));
// Copy to clipboard
const copyBtn = document.querySelector('.copy-btn');
if (copyBtn) {
copyBtn.addEventListener('click', () => {
navigator.clipboard.writeText('cargo add varvedb');
const originalIcon = copyBtn.innerHTML;
copyBtn.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="#4ade80" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>`;
setTimeout(() => {
copyBtn.innerHTML = originalIcon;
}, 2000);
});
}
// Interactive Diagram
const components = document.querySelectorAll('.arch-component, .arch-box');
const codeLines = document.querySelectorAll('.code-line');
components.forEach(comp => {
comp.addEventListener('mouseenter', (e) => {
e.stopPropagation();
const id = comp.getAttribute('data-id');
if (!id) return;
// Determine highlight color
let color = '#38bdf8'; // Default Cyan
if (comp.classList.contains('storage')) color = '#fbbf24'; // Yellow
// Set CSS variable for highlight color
document.documentElement.style.setProperty('--highlight-color', color);
// Highlight Diagram Components
components.forEach(c => {
c.classList.remove('highlight', 'dim'); // Reset state
if (c === comp || c.getAttribute('data-id') === id) {
c.classList.add('highlight');
} else if (c.contains(comp)) {
// If this component contains the hovered one (e.g. Engine contains Stream),
// do NOT dim it, but don't highlight it either.
// This ensures the parent doesn't fade out, which would fade out the child too.
} else {
c.classList.add('dim');
}
});
// Highlight Code Lines
codeLines.forEach(line => {
line.classList.remove('highlight', 'dim'); // Reset state
if (line.getAttribute('data-related-id') === id) {
line.classList.add('highlight');
} else {
line.classList.add('dim');
}
});
});
comp.addEventListener('mouseleave', () => {
// Reset Diagram
components.forEach(c => {
c.classList.remove('highlight', 'dim');
});
// Reset Code
codeLines.forEach(line => {
line.classList.remove('highlight', 'dim');
});
});
});
</script>