|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8" /> |
|
<title>LeRobot Worldwide Hackathon โ Winners</title> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
|
|
|
<script src="https://cdn.tailwindcss.com"></script> |
|
|
|
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script> |
|
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script> |
|
</head> |
|
<body class="bg-[#FF9D00]"> |
|
<div id="root"></div> |
|
|
|
<script type="text/javascript"> |
|
const { useState, useEffect } = React; |
|
|
|
const INTRO_VIDEO_DATASET = "https://huggingface.co/api/datasets/imstevenpmwork/hackaton_closure"; |
|
|
|
|
|
function parseRankTeam(path) { |
|
const name = path.split("/").pop(); |
|
const m = name.match(/^(\d+)-(\d+)-/); |
|
return m ? { rank: +m[1], team: +m[2] } : { rank: 0, team: "LeRobot" }; |
|
} |
|
|
|
function App() { |
|
const [introSrc, setIntroSrc] = useState(null); |
|
const [videos, setVideos] = useState([]); |
|
const [teamDatasets, setTeamDatasets] = useState({}); |
|
|
|
|
|
async function loadIntro() { |
|
if (!INTRO_VIDEO_DATASET) return; |
|
try { |
|
const res = await fetch( |
|
`https://datasets-server.huggingface.co/rows?dataset=${INTRO_VIDEO_DATASET}&config=default&split=train&offset=0&limit=1` |
|
); |
|
const json = await res.json(); |
|
const row = json.rows?.[0]?.row || {}; |
|
const url = row.video || Object.values(row).find((v) => typeof v === "string" && v.endsWith(".mp4")); |
|
if (url) setIntroSrc(url.startsWith("http") ? url : `https://huggingface.co/datasets/${INTRO_VIDEO_DATASET}/resolve/main/${url}`); |
|
} catch (err) { |
|
console.error("Intro video load failed", err); |
|
} |
|
} |
|
|
|
|
|
async function loadMainContent() { |
|
|
|
const treeRes = await fetch( |
|
"https://huggingface.co/api/datasets/maringetxway/all-winners/tree/main" |
|
); |
|
const tree = await treeRes.json(); |
|
const ranked = tree |
|
.filter((f) => f.path.endsWith(".mp4")) |
|
.map((f) => { |
|
const { rank, team } = parseRankTeam(f.path); |
|
return { |
|
url: `https://huggingface.co/datasets/maringetxway/all-winners/resolve/main/${encodeURIComponent( |
|
f.path |
|
)}`, |
|
rank, |
|
team, |
|
}; |
|
}) |
|
.sort((a, b) => a.rank - b.rank); |
|
setVideos(ranked); |
|
|
|
|
|
const dsRes = await fetch( |
|
"https://huggingface.co/api/datasets?author=maringetxway" |
|
); |
|
const dsList = await dsRes.json(); |
|
const map = {}; |
|
dsList.forEach(({ id }) => { |
|
const m = id.match(/maringetxway\/team[_-]?(\d+)/i); |
|
if (m) { |
|
const t = +m[1]; |
|
if (!map[t]) map[t] = []; |
|
map[t].push(`https://huggingface.co/spaces/lerobot/visualize_dataset?dataset=${id}`); |
|
} |
|
}); |
|
setTeamDatasets(map); |
|
} |
|
|
|
useEffect(() => { |
|
loadIntro(); |
|
loadMainContent(); |
|
}, []); |
|
|
|
|
|
return React.createElement( |
|
"div", |
|
{ className: "min-h-screen py-10 px-4 max-w-3xl mx-auto" }, |
|
|
|
|
|
React.createElement( |
|
"h1", |
|
{ className: "text-center text-4xl font-bold text-white mb-6 drop-shadow-lg" }, |
|
"LeRobot Worldwide Hackathon โ Winners" |
|
), |
|
|
|
|
|
React.createElement( |
|
"p", |
|
{ className: "text-white text-center whitespace-pre-line mb-6 leading-relaxed" }, |
|
[ |
|
React.createElement("span", { key: "b", className: "font-bold" }, "๐ โฌ15,000 in robotics hardware prizes in collaboration with Seeedstudio"), |
|
" to support prizes for 10 winning teams and help us celebrate open-source robotics on a global scale! " |
|
] |
|
), |
|
|
|
|
|
React.createElement( |
|
"p", |
|
{ className: "text-white text-center whitespace-pre-line mb-10 leading-relaxed" }, |
|
`๐ Hereโs a sneak peek at the prizes up for grabs: \n\n๐ฅ 1st to 3rd place teams: 1 Hope Jr Arm & 1 LeKiwi per team\n\n๐ฅ 4th and 5th place teams: 1 Hope Jr Arm per team\n\n๐ฅ 6th to 24th place teams: 1 LeKiwi per team\n\n๐ฅ 25th to 30th place teams: 1 SO-101 per team\n\nA huge shoutout to everyone for your hard work and passion! It was truly tough to pick the top 30 โ there were so many amazing demo videos, and weโre absolutely blown away. We also had a lot of laughs along the way!` |
|
), |
|
|
|
|
|
React.createElement( |
|
"div", |
|
{ className: "flex justify-center items-center gap-6 mb-10" }, |
|
React.createElement("img", { src: "seeedstudio.png", alt: "Seeed Studio logo", className: "h-12 w-auto" }), |
|
React.createElement("img", { src: "hf.png", alt: "Hugging Face logo", className: "h-12 w-auto" }) |
|
), |
|
|
|
|
|
(introSrc ? React.createElement( |
|
"section", |
|
{ className: "mb-16" }, |
|
React.createElement("video", { src: introSrc, controls: true, className: "w-full rounded-xl shadow-2xl mb-10" }) |
|
) : null), |
|
|
|
|
|
...videos.map((v, i) => React.createElement( |
|
"section", |
|
{ key: i, className: "mb-16" }, |
|
React.createElement( |
|
"h2", |
|
{ className: "text-2xl font-semibold text-white mb-4 flex items-center gap-2" }, |
|
`#${v.rank}`, |
|
React.createElement("span", { className: "text-base font-normal text-white/80" }, `โ Team ${v.team ?? "?"}`) |
|
), |
|
React.createElement("video", { src: v.url, controls: true, className: "w-full rounded-xl shadow-2xl" }), |
|
teamDatasets[parseInt(v.team)] ? React.createElement( |
|
"div", |
|
{ className: "mt-2 space-y-1" }, |
|
...teamDatasets[parseInt(v.team)].map((url, j) => React.createElement( |
|
"a", |
|
{ key: j, href: url, target: "_blank", className: "text-sm text-blue-200 underline hover:text-white" }, |
|
`Dataset: ${url.split("=")[1]}` |
|
)) |
|
) : null |
|
)), |
|
|
|
|
|
React.createElement( |
|
"div", |
|
{ className: "bg-white rounded-xl shadow-lg p-8 mt-20 flex justify-center" }, |
|
React.createElement("img", { src: "sponsors.png", alt: "Sponsors", className: "max-w-full h-auto" }) |
|
) |
|
); |
|
} |
|
|
|
ReactDOM.createRoot(document.getElementById("root")).render(React.createElement(App)); |
|
</script> |
|
</body> |
|
</html> |