'use client' import { useState, useEffect } from 'react' import Link from 'next/link' // Icons function IcoUsers({ className }: { className?: string }) { return } function IcoTask({ className }: { className?: string }) { return } function IcoFolder({ className }: { className?: string }) { return } function IcoCreditCard({ className }: { className?: string }) { return } function IcoLock({ className }: { className?: string }) { return } function IcoDoc({ className }: { className?: string }) { return } function IcoArrow({ className }: { className?: string }) { return } function IcoTerminal({ className }: { className?: string }) { return } function IcoEye({ className }: { className?: string }) { return } function IcoPin({ className }: { className?: string }) { return } // ─── Mini UI Previews ────────────────────────────────────────────────────────── function MiniMemberTable() { const [activeRow, setActiveRow] = useState(0) const members = [ { name: 'Alex Chen', tier: 'PLUS', status: 'current' }, { name: 'Jordan Mills', tier: 'BASIC', status: 'current' }, { name: 'Sam Rivera', tier: 'PLUS', status: 'late' }, { name: 'Casey Wong', tier: 'BASIC', status: 'current' }, ] useEffect(() => { const t = setInterval(() => setActiveRow(p => (p + 1) % members.length), 2000) return () => clearInterval(t) }, [members.length]) return (
Members {members.length}
{members.map((m, i) => (
{m.name.split(' ').map(n => n[0]).join('')}
{m.name} {m.tier}
))}
) } function MiniTaskList() { const [checkedIndex, setCheckedIndex] = useState(-1) const tasks = [ { title: 'Clean laser cutter lens', area: 'Laser' }, { title: 'Restock filament', area: '3D Print' }, { title: 'Update wiki docs', area: 'Admin' }, ] useEffect(() => { const t = setInterval(() => { setCheckedIndex(p => (p >= tasks.length - 1 ? -1 : p + 1)) }, 1500) return () => clearInterval(t) }, [tasks.length]) return (
Tasks +
{tasks.map((t, i) => (
{i <= checkedIndex && ( )}
{t.title} {t.area}
))}
) } function MiniProjectBoard() { const [movingCard, setMovingCard] = useState(0) useEffect(() => { const t = setInterval(() => setMovingCard(p => (p + 1) % 3), 2500) return () => clearInterval(t) }, []) const columns = ['BACKLOG', 'IN PROGRESS', 'DONE'] return (
Projects
{columns.map((col, colIndex) => (
{col}
{colIndex === movingCard && (

CNC Upgrade

)} {colIndex === 1 && colIndex !== movingCard && (

Network rack

)}
))}
) } function MiniPayments() { const [linking, setLinking] = useState(false) useEffect(() => { const t = setInterval(() => setLinking(p => !p), 2000) return () => clearInterval(t) }, []) return (
Payments 2 unlinked
PAYPAL $50.00 {linking ? 'LINKED' : '+ LINK'}
VENMO $75.00 LINKED
) } function MiniOps() { const [revealedIndex, setRevealedIndex] = useState(-1) const [tab, setTab] = useState<'secrets' | 'kb'>('secrets') const secrets = [ { label: 'WiFi Password', area: 'Network' }, { label: 'Alarm Code', area: 'Security' }, { label: 'PayPal API Key', area: 'Finance' }, ] const kb = [ { title: 'Open / Close Procedure', area: 'Ops', pinned: true }, { title: 'Laser Cutter Safety', area: 'Laser', pinned: false }, { title: 'Board Meeting Runbook', area: 'Admin', pinned: true }, ] useEffect(() => { if (tab !== 'secrets') return const t = setInterval(() => { setRevealedIndex(p => (p >= secrets.length - 1 ? -1 : p + 1)) }, 1800) return () => clearInterval(t) }, [tab, secrets.length]) useEffect(() => { const t = setInterval(() => { setTab(p => (p === 'secrets' ? 'kb' : 'secrets')) setRevealedIndex(-1) }, 5000) return () => clearInterval(t) }, []) return (
Ops
{(['secrets', 'kb'] as const).map(t => ( ))}
{tab === 'secrets' && secrets.map((s, i) => (
{s.label} {s.area}
{i === revealedIndex ? ( ••••1234 ) : ( reveal )}
))} {tab === 'kb' && kb.map((k) => (
{k.title} {k.pinned && } {k.area}
))}
) } function MiniDashboard() { const [tick, setTick] = useState(0) useEffect(() => { const t = setInterval(() => setTick(p => p + 1), 3000) return () => clearInterval(t) }, []) const members = 47 + (tick % 3) return (
Members

{members}

Tasks

12

Due this week 3 late
{Array.from({ length: 12 }).map((_, i) => (
))}
) } // ─── Main Landing Page ───────────────────────────────────────────────────────── export default function LandingPage() { return (
{/* Nav */} {/* Hero */}

Operational software for makerspaces

Run your hackerspace like the infrastructure it is

Member management, dues tracking, task coordination, project visibility, and a shared ops brain for the things that keep the space running.

Get Started Log in
{/* Features */}

Features

Everything your space needs, nothing it does not

No bloated enterprise features. No learning curve. Tools that match how hackerspaces actually operate.

{[ { Icon: IcoUsers, title: 'Member Directory', description: 'Track membership tiers, payment status, and contact info. Bulk actions for common operations. Know who is current and who is not.', preview: , }, { Icon: IcoTask, title: 'Task Board', description: 'Chores, maintenance, and one-off tasks with assignments, due dates, and recurring schedules. Claim and complete from anywhere.', preview: , }, { Icon: IcoFolder, title: 'Project Tracking', description: 'Kanban board for space projects. Track progress, assign areas, and keep the community informed about what is in motion.', preview: , }, { Icon: IcoCreditCard, title: 'Payment Reconciliation', description: 'Import from PayPal, Venmo, and Zeffy. Link transactions to members. Know exactly who owes what without the spreadsheet.', preview: , }, { Icon: IcoLock, title: 'Ops: Secrets and KB', description: 'Store WiFi passwords, alarm codes, API keys, and procedures in one place. Role-based visibility. Reveal on demand.', preview: , }, { Icon: IcoDoc, title: 'Dashboard', description: 'At a glance status on membership, open tasks, payment issues, and recent activity. Know what needs attention when you log in.', preview: , }, ].map((feature) => (

{feature.title}

{feature.description}

{feature.preview}
))}
{/* How it works */}

Setup

From nothing to running in under an hour

{[ { step: '01', title: 'Import your members', description: 'Paste from a spreadsheet or add them one by one. Set tiers, statuses, and contact info.', }, { step: '02', title: 'Connect payments', description: 'Link your PayPal or Zeffy account. Transactions import and sit waiting to be matched to members.', }, { step: '03', title: 'Seed your ops docs', description: 'Drop in your SOPs, credentials, and area leads. The whole board has one place to look things up.', }, ].map((item) => (

{item.step}

{item.title}

{item.description}

))}
{/* CTA */}

Your space deserves better than spreadsheets

A tool built specifically for volunteer-run makerspaces and hackerspaces. Not adapted from something else.

Get Started Log in
{/* Footer */}
) }