Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sass/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
--border-subtle: #d9d1bd;
--text: #1a2235; // deep navy — high AA on cream
--text-dim: #44516a;
--text-faint: #6b7280;
--text-faint: #586273; // bumped from #6b7280 (4.4:1) to clear AA 4.5:1 on cream — sunlight-legibility fix
--accent: #3a5fce; // darkened accent for AA on cream
--accent-hover: #2747ad;
--accent-glow: rgba(58, 95, 206, 0.10);
Expand Down
26 changes: 23 additions & 3 deletions static/cube.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,15 @@
});
}

if (reduceMotion) {
// Honor prefers-reduced-motion: snap to target rotation, no zoom/rotate animations.
cube.style.transition = 'none';
scene.style.transition = 'none';
apply();
if (detailPanel) detailPanel.classList.add('cube-detail--open');
return;
}

// Animate: rotate the cube
cube.style.transition = 'transform 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94)';
apply();
Expand All @@ -177,12 +186,23 @@
// Hide detail
if (detailPanel) detailPanel.classList.remove('cube-detail--open');

// Zoom back in
scene.style.transform = 'scale(1)';

// Return to isometric
rotX = -30;
rotY = 35;

if (reduceMotion) {
cube.style.transition = 'none';
scene.style.transition = 'none';
scene.style.transform = 'scale(1)';
apply();
autoSpin = true;
snaps.forEach(function (b) { b.classList.remove('face-btn--active'); });
return;
}

// Zoom back in
scene.style.transform = 'scale(1)';

cube.style.transition = 'transform 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94)';
apply();

Expand Down
15 changes: 15 additions & 0 deletions static/theme-toggle.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,24 @@
return 'dark';
}

// Sync ARIA state to the rendered theme. aria-pressed="true" when light
// is active (the non-default state); aria-label describes what the click
// would *do*, which is what screen readers announce.
function syncAria() {
var theme = currentTheme();
btn.setAttribute('aria-pressed', theme === 'light' ? 'true' : 'false');
btn.setAttribute(
'aria-label',
theme === 'light' ? 'Switch to dark theme' : 'Switch to light theme'
);
}

syncAria();

btn.addEventListener('click', function () {
var next = currentTheme() === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', next);
try { localStorage.setItem(STORAGE_KEY, next); } catch (e) { /* private mode */ }
syncAria();
});
})();
13 changes: 5 additions & 8 deletions templates/projects.html
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,6 @@ <h1 class="section-heading">{{ section.title }}</h1>
<span class="face-tool__name">Lean 4</span>
<span class="face-tool__desc">scheduling theory</span>
</a>
<a href="https://github.com/pulseengine/witness" class="face-tool" rel="noopener">
<span class="face-tool__name">witness</span>
<span class="face-tool__desc">MC/DC on Wasm IR</span>
</a>
</div>
<div class="face-divider"></div>
<div class="face-edge">
Expand Down Expand Up @@ -219,14 +215,13 @@ <h3 style="color:#22d3ee">Build — the pipeline</h3>
</div>

<div class="cube-detail__panel" data-detail="verify" style="display:none">
<h3 style="color:#4ade80">Verify — three proof paths and the empirical coverage cell</h3>
<p><strong>Verus</strong> proves Rust code via SMT/Z3 — preconditions, postconditions, invariants on every public function. <strong>Rocq</strong> machine-checks abstract invariants that hold regardless of implementation. <strong>Lean 4</strong> proves scheduling theory — priority inheritance, deadline guarantees, starvation freedom. <strong>witness</strong> measures branch / MC/DC coverage at the post-compile WebAssembly level — the empirical counterpart that closes the §FM.6.7(f) / structural-coverage cell DO-178C, ISO 26262 Part 6 Table 12, and IEC 61508 Annex C expect.</p>
<p>These are not limited to one tool. Every component in the ecosystem — meld, loom, synth, kiln, gale, relay, wohl — carries formal verification. Four independent verification paths run in CI on every commit: three proof, one coverage.</p>
<h3 style="color:#4ade80">Verify — three independent proof paths across everything</h3>
<p><strong>Verus</strong> proves Rust code via SMT/Z3 — preconditions, postconditions, invariants on every public function. <strong>Rocq</strong> machine-checks abstract invariants that hold regardless of implementation. <strong>Lean 4</strong> proves scheduling theory — priority inheritance, deadline guarantees, starvation freedom.</p>
<p>These are not limited to one tool. Every component in the ecosystem — meld, loom, synth, kiln, gale, relay, wohl — carries formal verification. Three independent paths run in CI on every commit.</p>
<div class="cube-detail__links">
<a href="https://github.com/pulseengine/rules_verus" rel="noopener">rules_verus</a>
<a href="https://github.com/pulseengine/rules_rocq_rust" rel="noopener">rules_rocq_rust</a>
<a href="https://github.com/pulseengine/rules_lean" rel="noopener">rules_lean</a>
<a href="https://github.com/pulseengine/witness" rel="noopener">witness</a>
<a href="https://github.com/pulseengine/gale" rel="noopener">gale</a>
</div>
</div>
Expand Down Expand Up @@ -532,6 +527,8 @@ <h3 style="color:#c084fc">Agent — AI-native development</h3>
.cube__face--bottom { transform: rotateX(-90deg) translateZ(135px); }
.cube-wrap { padding: 2.5rem 0 2rem; }
.face-component__name { font-size: 1.1rem; }
/* Hit-target fix — iOS guideline is 44×44 minimum for touchable controls. */
.face-btn { min-height: 44px; padding: 0.6rem 0.9rem; font-size: 0.875rem; }
}

@media (prefers-reduced-motion: reduce) {
Expand Down
Loading