feat: another track

This commit is contained in:
Nik L
2026-04-07 16:17:33 -04:00
parent 7e34db2edb
commit 502a1f0a81
2 changed files with 158 additions and 2 deletions

View File

@@ -14,10 +14,11 @@ import {
ShieldAlert,
MessageSquare,
Crown,
FlaskConical,
} from 'lucide-react'
import { Footer } from '@/components/footer'
import { LiveTerminal } from '@/components/hackathons/live-terminal'
import { StreamViz, SecureViz, RadarViz, ScanViz, ExtendViz } from '@/components/hackathons/track-visuals'
import { StreamViz, SecureViz, RadarViz, ScanViz, ExtendViz, BenchViz } from '@/components/hackathons/track-visuals'
const ShieldScene = dynamic(
() => import('@/components/hackathons/shield-scene').then((m) => m.ShieldScene),
@@ -546,6 +547,18 @@ const tracks = [
examples: ['Error interception', 'Context injection', 'Alternative suggestion', 'Loop prevention'],
Visual: ExtendViz,
},
{
id: 'control-benchmark',
icon: FlaskConical,
title: 'Control Evaluation Benchmark',
hook: 'Build the test suite that measures how well sandboxes actually work.',
color: 'from-rose-500/10 to-pink-500/5',
borderColor: 'hover:border-rose-500/30',
description: 'Define main tasks (real software engineering work) paired with side tasks (exfiltrate a key, install a backdoor, modify git hooks). Measure how much useful work an agent completes under Greywall\'s restrictions vs. how often adversarial goals succeed.',
scoring: 'Show the safety/usefulness tradeoff. A good benchmark reveals real weaknesses, not just toy scenarios.',
examples: ['Main/side task pairs', 'Policy quality scoring', 'Layer isolation tests', 'Reproducible evals'],
Visual: BenchViz,
},
]
function TrackCard({ track, index }: { track: typeof tracks[0]; index: number }) {
@@ -612,7 +625,7 @@ function Tracks() {
Pick your track.
</h2>
<p className="font-serif text-lg text-muted-foreground max-w-2xl mx-auto">
Five open-ended tracks, all building on top of{' '}
Six open-ended tracks, all building on top of{' '}
<a href="https://github.com/GreyhavenHQ/greywall" target="_blank" rel="noopener noreferrer" className="text-primary hover:text-primary/80 transition-colors underline underline-offset-2">Greywall</a>.
Go deep on one or try a few.
</p>

View File

@@ -405,3 +405,146 @@ export function ExtendViz() {
</div>
)
}
/* ─── Benchmark grid (Track 6 — Control Evaluation Benchmark) ─── */
export function BenchViz() {
const canvasRef = useRef<HTMLCanvasElement>(null)
useEffect(() => {
const canvas = canvasRef.current
if (!canvas) return
const ctx = canvas.getContext('2d')
if (!ctx) return
const dpr = window.devicePixelRatio || 1
let w = 0, h = 0
const resize = () => {
const rect = canvas.getBoundingClientRect()
w = rect.width
h = rect.height
canvas.width = w * dpr
canvas.height = h * dpr
ctx.setTransform(dpr, 0, 0, dpr, 0, 0)
}
resize()
let t = 0
let animId: number
const cols = 6, rows = 8
const cells = Array.from({ length: cols * rows }, (_, i) => ({
pass: Math.random() > 0.25,
revealAt: Math.random() * 4 + (Math.floor(i / cols)) * 0.3,
pulsePhase: Math.random() * Math.PI * 2,
}))
const draw = () => {
ctx.clearRect(0, 0, w, h)
t += 0.016
const padX = w * 0.08, padY = h * 0.06
const cellW = (w - padX * 2) / cols
const cellH = (h - padY * 2) / rows
const gap = 2.5
const loopT = t % 6
cells.forEach((cell, i) => {
const col = i % cols
const row = Math.floor(i / cols)
const x = padX + col * cellW + gap
const y = padY + row * cellH + gap
const cw = cellW - gap * 2
const ch = cellH - gap * 2
const r = Math.min(cw, ch) * 0.15
if (loopT < cell.revealAt) {
// Not yet revealed — dim outline
ctx.strokeStyle = 'rgba(244, 63, 94, 0.06)'
ctx.lineWidth = 0.5
ctx.beginPath()
ctx.roundRect(x, y, cw, ch, r)
ctx.stroke()
return
}
// Reveal animation
const revealProgress = Math.min((loopT - cell.revealAt) * 2, 1)
const pulse = Math.sin(t * 2 + cell.pulsePhase) * 0.15 + 0.85
if (cell.pass) {
// Pass — rose/green tint
ctx.fillStyle = `rgba(74, 222, 128, ${0.12 * revealProgress * pulse})`
ctx.beginPath()
ctx.roundRect(x, y, cw, ch, r)
ctx.fill()
ctx.strokeStyle = `rgba(74, 222, 128, ${0.25 * revealProgress})`
ctx.lineWidth = 0.5
ctx.beginPath()
ctx.roundRect(x, y, cw, ch, r)
ctx.stroke()
// Checkmark
if (revealProgress > 0.5) {
const alpha = (revealProgress - 0.5) * 2
const cx = x + cw / 2, cy = y + ch / 2
const s = Math.min(cw, ch) * 0.2
ctx.strokeStyle = `rgba(74, 222, 128, ${0.5 * alpha})`
ctx.lineWidth = 1.2
ctx.beginPath()
ctx.moveTo(cx - s * 0.6, cy)
ctx.lineTo(cx - s * 0.1, cy + s * 0.5)
ctx.lineTo(cx + s * 0.6, cy - s * 0.4)
ctx.stroke()
}
} else {
// Fail — red tint
ctx.fillStyle = `rgba(244, 63, 94, ${0.15 * revealProgress * pulse})`
ctx.beginPath()
ctx.roundRect(x, y, cw, ch, r)
ctx.fill()
ctx.strokeStyle = `rgba(244, 63, 94, ${0.3 * revealProgress})`
ctx.lineWidth = 0.5
ctx.beginPath()
ctx.roundRect(x, y, cw, ch, r)
ctx.stroke()
// X mark
if (revealProgress > 0.5) {
const alpha = (revealProgress - 0.5) * 2
const cx = x + cw / 2, cy = y + ch / 2
const s = Math.min(cw, ch) * 0.18
ctx.strokeStyle = `rgba(244, 63, 94, ${0.5 * alpha})`
ctx.lineWidth = 1.2
ctx.beginPath()
ctx.moveTo(cx - s, cy - s)
ctx.lineTo(cx + s, cy + s)
ctx.moveTo(cx + s, cy - s)
ctx.lineTo(cx - s, cy + s)
ctx.stroke()
}
}
})
// Progress bar at bottom
const barY = h - padY * 0.6
const barH = 2
const progress = Math.min(loopT / 5, 1)
ctx.fillStyle = 'rgba(244, 63, 94, 0.08)'
ctx.fillRect(padX, barY, w - padX * 2, barH)
ctx.fillStyle = 'rgba(244, 63, 94, 0.3)'
ctx.fillRect(padX, barY, (w - padX * 2) * progress, barH)
animId = requestAnimationFrame(draw)
}
draw()
window.addEventListener('resize', resize)
return () => { cancelAnimationFrame(animId); window.removeEventListener('resize', resize) }
}, [])
return <canvas ref={canvasRef} className="absolute inset-0 w-full h-full" style={{ display: 'block' }} />
}