import React, { useEffect, useMemo, useRef, useState } from 'react'
const nf = new Intl.NumberFormat('en-US')
const fmt = (n) => (n == null ? '—' : nf.format(n))
const FAMILIES = [
{ key: 'imajev', label: 'Imajev', sub: 'vision decision models', match: /imajev/, chip: 'bg-[var(--accent)] text-black' },
{ key: 'jevk5', label: 'JevK5', sub: 'decision models', match: /jevk5/, chip: 'bg-emerald-400/90 text-black' },
{ key: 'decider', label: 'Decider', sub: 'typed decisions', match: /decider/, chip: 'bg-sky-400/90 text-black' },
{ key: 'train', label: 'Training & Experiments', sub: '', match: /qwen|grpo|t5|gemma|sdxl|kaggle|sft|dpo|colab|needle|arithmetic|sailing|functiongemma|reward|falcon|offload|outputs|selftest/i, fold: true },
{ key: 'legacy', label: 'Legacy', sub: '', match: /./, fold: true },
]
function dailyDeltas(series) {
const out = []
for (let i = 1; i < series.length; i++) out.push([series[i][0], Math.max(0, series[i][1] - series[i - 1][1])])
return out
}
function sumLast(deltas, n) {
const t = deltas.slice(-n)
return t.reduce((a, x) => a + x[1], 0)
}
function useCountUp(target, dur = 900) {
const [v, setV] = useState(0)
useEffect(() => {
let raf
const t0 = performance.now()
const tick = (t) => {
const p = Math.min(1, (t - t0) / dur)
setV(Math.round(target * (1 - Math.pow(1 - p, 3))))
if (p < 1) raf = requestAnimationFrame(tick)
}
raf = requestAnimationFrame(tick)
return () => cancelAnimationFrame(raf)
}, [target, dur])
return v
}
function Sparkline({ data, w = 96, h = 28, color = 'var(--accent)' }) {
if (!data.length) return null
const max = Math.max(1, ...data.map((d) => d[1]))
const pts = data.map((d, i) => [
(i / Math.max(1, data.length - 1)) * (w - 4) + 2,
h - 3 - (d[1] / max) * (h - 8),
])
const line = pts.map((p, i) => (i ? 'L' : 'M') + p[0].toFixed(1) + ' ' + p[1].toFixed(1)).join(' ')
const area = line + ' L' + pts[pts.length - 1][0].toFixed(1) + ' ' + (h - 1) + ' L' + pts[0][0].toFixed(1) + ' ' + (h - 1) + ' Z'
return (
)
}
function BigChart({ model }) {
const wrapRef = useRef(null)
const [hover, setHover] = useState(null)
const daily = useMemo(() => dailyDeltas(model.series), [model])
const cum = useMemo(() => daily.map((d, i) => [d[0], model.series[i + 1][1]]), [model])
const W = 1000, H = 300, pad = { l: 52, r: 16, t: 18, b: 28 }
if (daily.length < 2) {
return (
Not enough history yet — first snapshot {model.series[0] ? model.series[0][0] : '?'} · come back tomorrow.
)
}
const dmax = Math.max(1, ...daily.map((d) => d[1]))
const cmax = Math.max(1, ...cum.map((d) => d[1]))
const iw = W - pad.l - pad.r, ih = H - pad.t - pad.b
const x = (i) => pad.l + (i / (daily.length - 1)) * iw
const yd = (v) => pad.t + ih - (v / dmax) * ih
const yc = (v) => pad.t + ih - (v / cmax) * ih
const cpts = cum.map((d, i) => x(i).toFixed(1) + ',' + yc(d[1]).toFixed(1)).join(' ')
const bars = daily.map((d, i) => {
const bw = Math.max(2, iw / daily.length - 2)
return (
{d[0] + ': ' + fmt(d[1]) + ' downloads'}
)
})
const grid = [0, 1, 2, 3, 4].map((g) => {
const gy = pad.t + ih - (g / 4) * ih
return (
{fmt(Math.round((dmax * g) / 4))}
)
})
const onMove = (e) => {
const rect = wrapRef.current.getBoundingClientRect()
const rel = (e.clientX - rect.left) / rect.width
const i = Math.max(0, Math.min(daily.length - 1, Math.round(rel * (daily.length - 1))))
setHover(i)
}
const hd = hover != null ? daily[hover] : null
return (
setHover(null)}>
{hd && (
{hd[0]}
{fmt(hd[1])} downloads/day
{fmt(cum[hover][1])} all time
)}
)
}
function Stat({ k, v, d, dCls = '' }) {
const n = useCountUp(v)
return (
)
}
function ModelDetail({ model, live, onClose }) {
const daily = useMemo(() => dailyDeltas(model.series), [model])
const best = daily.reduce((a, d) => (d[1] > (a ? a[1] : 0) ? d : a), null)
const all = live?.downloads ?? model.downloadsAllTime
return (
{model.id}
{fmt(all)} all time
best day {best ? fmt(best[1]) : '—'} {best ? best[0] : ''}
♥ {fmt(live?.likes ?? model.likes)}
{model.created && since {model.created}}
downloads / day
cumulative
)
}
function ModelRow({ m, live, open, onToggle }) {
const deltas = useMemo(() => dailyDeltas(m.series), [m])
const d7 = sumLast(deltas, 7)
const all = live?.downloads ?? m.downloadsAllTime
const short = m.id.replace('mindchain/', '')
return (
<>
{ if (e.key === "Enter") onToggle() }} className="group cursor-pointer border-b border-[var(--line2)] transition-colors hover:bg-[var(--accent-soft)]/40">
|
mindchain/{short}
{m.pipeline && {m.pipeline} }
|
|
{fmt(all)} |
0 ? 'text-[var(--up)]' : 'text-[var(--faint)]')}>
{d7 > 0 ? '+' + fmt(d7) : '0'}
|
♥ {fmt(live?.likes ?? m.likes)} |
{open && (
|
|
)}
>
)
}
function SkeletonRow() {
return (
|
|
|
|
|
)
}
export default function App() {
const [data, setData] = useState(null)
const [error, setError] = useState(false)
const [live, setLive] = useState({})
const [liveOk, setLiveOk] = useState(false)
const [openId, setOpenId] = useState(null)
const [query, setQuery] = useState('')
const [sortBy, setSortBy] = useState('downloads')
const [theme, setTheme] = useState(() => (localStorage.getItem('mf-theme') || 'dark'))
const searchRef = useRef(null)
useEffect(() => {
document.documentElement.classList.toggle('light', theme === 'light')
localStorage.setItem('mf-theme', theme)
}, [theme])
useEffect(() => {
fetch('data.json').then((r) => { if (!r.ok) throw new Error(r.status); return r.json() })
.then((d) => setData(d)).catch(() => setError(true))
}, [])
useEffect(() => {
fetch('https://huggingface.co/api/models?author=mindchain&limit=100&full=true')
.then((r) => { if (!r.ok) throw new Error(r.status); return r.json() })
.then((arr) => { const map = {}; arr.forEach((m) => (map[m.id] = m)); setLive(map); setLiveOk(true) })
.catch(() => setLiveOk(false))
}, [])
useEffect(() => {
const apply = () => {
const match = location.hash.startsWith('#/m/') ? location.hash.slice(4) : null
setOpenId(match ? decodeURIComponent(match) : null)
}
apply()
window.addEventListener('hashchange', apply)
return () => window.removeEventListener('hashchange', apply)
}, [])
useEffect(() => {
const onKey = (e) => {
if (e.key === '/' && document.activeElement !== searchRef.current) { e.preventDefault(); searchRef.current?.focus() }
if (e.key === 'Escape') { setOpenId(null); history.replaceState(null, '', location.pathname); searchRef.current?.blur() }
}
window.addEventListener('keydown', onKey)
return () => window.removeEventListener('keydown', onKey)
}, [])
const toggle = (id) => {
if (openId === id) { setOpenId(null); history.replaceState(null, '', location.pathname) }
else { setOpenId(id); location.hash = '#/m/' + encodeURIComponent(id) }
}
const models = data?.models ?? []
const get = (m, k) => (k === 'downloads' ? (live[m.id]?.downloads ?? m.downloadsAllTime) : k === 'delta7' ? sumLast(dailyDeltas(m.series), 7) : m.id)
const groups = useMemo(() => {
const q = query.trim().toLowerCase()
const out = []
for (const f of FAMILIES) {
let ms = models.filter((m) => f.match.test(m.id))
if (q) ms = ms.filter((m) => m.id.toLowerCase().includes(q))
ms = ms.slice().sort((a, b) => (sortBy === 'name' ? a.id.localeCompare(b.id) : get(b, sortBy) - get(a, sortBy)))
if (ms.length) out.push({ ...f, models: ms })
}
return out
}, [models, query, sortBy, live])
const port = models.filter((m) => /imajev|jevk5|decider/.test(m.id))
const tot = (arr) => arr.reduce((a, m) => a + (live[m.id]?.downloads ?? m.downloadsAllTime), 0)
const d7all = models.reduce((a, m) => a + sumLast(dailyDeltas(m.series), 7), 0)
const d7prev = models.reduce((a, m) => { const t = dailyDeltas(m.series).slice(-14, -7); return a + t.reduce((x, y) => x + y[1], 0) }, 0)
let best = { v: 0, day: null }
models.forEach((m) => dailyDeltas(m.series).forEach((d) => { if (d[1] > best.v) best = { v: d[1], day: d[0] } }))
const lastDay = models[0]?.series[models[0].series.length - 1]?.[0]
return (
Every download of the mindchain portfolio, day by day.
Imajev, JevK5 and Decider — decision models that run on an 8 GB card.
Numbers overlay live from the {' '}
Hub API,
history comes from daily snapshots.
{error && (
Could not load the download history.
)}
{!data && !error && (
{[0, 1, 2, 3, 4].map((i) => (
))}
{[0, 1, 2, 3, 4, 5].map((i) => ())}
)}
{data && (
<>
a + (live[m.id]?.likes ?? m.likes), 0)} d="on the hub" />
{groups.length === 0 && (
No models match {query}
)}
{groups.map((g) => {
const gtot = tot(g.models)
return (
{g.label}
{g.sub && · {g.sub}}
{g.models.length} models · {fmt(gtot)} downloads
| Model |
Last 10 days |
All time |
Δ 7d |
♥ |
{g.models.map((m) => (
toggle(m.id)} />
))}
)
})}
>
)}
)
}