feat: hackathon page mvp
This commit is contained in:
@@ -136,7 +136,225 @@ export function SecureViz() {
|
||||
)
|
||||
}
|
||||
|
||||
/* ─── Floating code snippets (Track 3) ─── */
|
||||
/* ─── Radar sweep (Track 3 — Derail Detection) ─── */
|
||||
|
||||
export function RadarViz() {
|
||||
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 blips = Array.from({ length: 6 }, () => ({
|
||||
angle: Math.random() * Math.PI * 2,
|
||||
dist: 0.3 + Math.random() * 0.55,
|
||||
flash: 0,
|
||||
}))
|
||||
|
||||
const draw = () => {
|
||||
ctx.clearRect(0, 0, w, h)
|
||||
t += 0.012
|
||||
|
||||
const cx = w / 2, cy = h / 2
|
||||
const maxR = Math.min(w, h) * 0.42
|
||||
|
||||
// Concentric rings
|
||||
for (let i = 1; i <= 3; i++) {
|
||||
ctx.beginPath()
|
||||
ctx.arc(cx, cy, maxR * (i / 3), 0, Math.PI * 2)
|
||||
ctx.strokeStyle = `rgba(245, 158, 11, ${0.06 + i * 0.02})`
|
||||
ctx.lineWidth = 0.5
|
||||
ctx.stroke()
|
||||
}
|
||||
|
||||
// Cross lines
|
||||
ctx.strokeStyle = 'rgba(245, 158, 11, 0.06)'
|
||||
ctx.lineWidth = 0.5
|
||||
ctx.beginPath(); ctx.moveTo(cx - maxR, cy); ctx.lineTo(cx + maxR, cy); ctx.stroke()
|
||||
ctx.beginPath(); ctx.moveTo(cx, cy - maxR); ctx.lineTo(cx, cy + maxR); ctx.stroke()
|
||||
|
||||
// Sweep line
|
||||
const sweepAngle = t * 1.5
|
||||
const sx = cx + Math.cos(sweepAngle) * maxR
|
||||
const sy = cy + Math.sin(sweepAngle) * maxR
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(cx, cy)
|
||||
ctx.lineTo(sx, sy)
|
||||
ctx.strokeStyle = 'rgba(245, 158, 11, 0.3)'
|
||||
ctx.lineWidth = 1
|
||||
ctx.stroke()
|
||||
|
||||
// Sweep trail (fading arc segments)
|
||||
const trailLength = 0.6
|
||||
const segments = 12
|
||||
for (let s = 0; s < segments; s++) {
|
||||
const frac = s / segments
|
||||
const a0 = sweepAngle - trailLength * (1 - frac)
|
||||
const a1 = sweepAngle - trailLength * (1 - (s + 1) / segments)
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(cx, cy)
|
||||
ctx.arc(cx, cy, maxR, a0, a1)
|
||||
ctx.closePath()
|
||||
ctx.fillStyle = `rgba(245, 158, 11, ${frac * 0.08})`
|
||||
ctx.fill()
|
||||
}
|
||||
|
||||
// Blips
|
||||
blips.forEach((b) => {
|
||||
const angleDiff = ((sweepAngle % (Math.PI * 2)) - b.angle + Math.PI * 4) % (Math.PI * 2)
|
||||
if (angleDiff < 0.15) b.flash = 1
|
||||
b.flash *= 0.96
|
||||
if (b.flash > 0.01) {
|
||||
const bx = cx + Math.cos(b.angle) * maxR * b.dist
|
||||
const by = cy + Math.sin(b.angle) * maxR * b.dist
|
||||
ctx.beginPath()
|
||||
ctx.arc(bx, by, 2 + b.flash * 2, 0, Math.PI * 2)
|
||||
ctx.fillStyle = `rgba(245, 158, 11, ${b.flash * 0.6})`
|
||||
ctx.fill()
|
||||
}
|
||||
})
|
||||
|
||||
// Center dot
|
||||
ctx.beginPath()
|
||||
ctx.arc(cx, cy, 2.5, 0, Math.PI * 2)
|
||||
ctx.fillStyle = 'rgba(245, 158, 11, 0.5)'
|
||||
ctx.fill()
|
||||
|
||||
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' }} />
|
||||
}
|
||||
|
||||
/* ─── Scanning grid (Track 4 — Malicious Request Detection) ─── */
|
||||
|
||||
export function ScanViz() {
|
||||
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 cells = Array.from({ length: 40 }, () => ({
|
||||
col: Math.floor(Math.random() * 8),
|
||||
row: Math.floor(Math.random() * 10),
|
||||
threat: Math.random() < 0.25,
|
||||
flash: 0,
|
||||
}))
|
||||
|
||||
const draw = () => {
|
||||
ctx.clearRect(0, 0, w, h)
|
||||
t += 0.015
|
||||
|
||||
const cellW = w / 8, cellH = h / 10
|
||||
|
||||
// Grid lines
|
||||
for (let i = 0; i <= 8; i++) {
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(i * cellW, 0); ctx.lineTo(i * cellW, h)
|
||||
ctx.strokeStyle = 'rgba(6, 182, 212, 0.06)'
|
||||
ctx.lineWidth = 0.5
|
||||
ctx.stroke()
|
||||
}
|
||||
for (let i = 0; i <= 10; i++) {
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(0, i * cellH); ctx.lineTo(w, i * cellH)
|
||||
ctx.strokeStyle = 'rgba(6, 182, 212, 0.06)'
|
||||
ctx.lineWidth = 0.5
|
||||
ctx.stroke()
|
||||
}
|
||||
|
||||
// Scan line (horizontal, sweeping down)
|
||||
const scanY = (t * 0.5 % 1) * h
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(0, scanY); ctx.lineTo(w, scanY)
|
||||
ctx.strokeStyle = 'rgba(6, 182, 212, 0.4)'
|
||||
ctx.lineWidth = 1.5
|
||||
ctx.stroke()
|
||||
|
||||
// Scan line glow
|
||||
const scanGrad = ctx.createLinearGradient(0, scanY - 30, 0, scanY)
|
||||
scanGrad.addColorStop(0, 'rgba(6, 182, 212, 0)')
|
||||
scanGrad.addColorStop(1, 'rgba(6, 182, 212, 0.06)')
|
||||
ctx.fillStyle = scanGrad
|
||||
ctx.fillRect(0, scanY - 30, w, 30)
|
||||
|
||||
// Cells
|
||||
cells.forEach((c) => {
|
||||
const cellY = c.row * cellH + cellH / 2
|
||||
if (Math.abs(scanY - cellY) < cellH * 0.7) c.flash = 1
|
||||
c.flash *= 0.97
|
||||
|
||||
if (c.flash > 0.01) {
|
||||
const x = c.col * cellW + cellW * 0.15
|
||||
const y = c.row * cellH + cellH * 0.15
|
||||
const cw = cellW * 0.7, ch = cellH * 0.7
|
||||
ctx.fillStyle = c.threat
|
||||
? `rgba(239, 68, 68, ${c.flash * 0.15})`
|
||||
: `rgba(6, 182, 212, ${c.flash * 0.08})`
|
||||
ctx.fillRect(x, y, cw, ch)
|
||||
|
||||
if (c.threat && c.flash > 0.3) {
|
||||
ctx.strokeStyle = `rgba(239, 68, 68, ${c.flash * 0.3})`
|
||||
ctx.lineWidth = 0.8
|
||||
ctx.strokeRect(x, y, cw, ch)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
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' }} />
|
||||
}
|
||||
|
||||
/* ─── Floating code snippets (Track 5 — Response Rewriting) ─── */
|
||||
|
||||
export function ExtendViz() {
|
||||
const snippets = [
|
||||
|
||||
Reference in New Issue
Block a user