Sergei Argutin
Fix premium sample asset paths
04a7d02
Raw
History Blame Contribute Delete
15.8 kB
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Free Exercise Dataset — 400 Exercises, JSON + Images (EN/DE/ES) · RepDB</title>
<meta name="description" content="Browse RepDB's free exercise dataset: 400 exercises in JSON with flat illustrations, target muscles, equipment, MET, and EN/DE/ES instructions. Free for commercial in-app use with attribution. Full paid dataset at repdb.co." />
<link rel="canonical" href="https://repdb.co/free-exercise-dataset" />
<meta property="og:title" content="Free Exercise Dataset — 400 Exercises (RepDB)" />
<meta property="og:description" content="400 fitness exercises in JSON with illustrations, muscles, equipment and EN/DE/ES instructions. Free with attribution. The full paid dataset keeps growing at repdb.co." />
<meta property="og:type" content="website" />
<meta property="og:image" content="https://sergei-argutin.github.io/exercise-dataset/images/flat/squat-peak.webp" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Dataset",
"name": "RepDB Exercise Dataset (free tier)",
"description": "Free multilingual fitness exercise dataset: exercises in JSON with flat WebP illustrations, target muscles, equipment, MET values, and step-by-step instructions in English, German and Spanish. Free for personal and commercial in-app use with attribution.",
"url": "https://sergei-argutin.github.io/exercise-dataset/",
"license": "https://github.com/sergei-argutin/exercise-dataset/blob/main/LICENSE-DATA.md",
"isAccessibleForFree": true,
"inLanguage": ["en", "de", "es"],
"creator": {
"@type": "Organization",
"name": "RepDB",
"url": "https://repdb.co"
},
"distribution": {
"@type": "DataDownload",
"encodingFormat": "application/json",
"contentUrl": "https://raw.githubusercontent.com/sergei-argutin/exercise-dataset/main/exercises.json"
}
}
</script>
<style>
:root{--bg:#0b0c0f;--card:#15171c;--mut:#9aa3af;--fg:#f3f4f6;--acc:#22c55e;--line:#252830}
*{box-sizing:border-box}
body{margin:0;font:15px/1.5 system-ui,-apple-system,Segoe UI,Roboto,sans-serif;background:var(--bg);color:var(--fg)}
a{color:var(--acc)}
header{padding:28px 20px 14px;max-width:1100px;margin:0 auto}
h1{font-size:1.7rem;margin:0 0 6px}
.sub{color:var(--mut);margin:0 0 14px}
.cta{display:inline-block;background:var(--acc);color:#06210f;font-weight:700;text-decoration:none;padding:9px 16px;border-radius:9px}
.bar{display:flex;gap:10px;flex-wrap:wrap;align-items:center;max-width:1100px;margin:8px auto 0;padding:0 20px}
input,select{background:var(--card);border:1px solid var(--line);color:var(--fg);padding:9px 11px;border-radius:8px;font-size:14px}
input{flex:1;min-width:180px}
main{max-width:1100px;margin:18px auto 60px;padding:0 20px}
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));gap:14px}
.card{position:relative;background:var(--card);border:1px solid var(--line);border-radius:12px;overflow:hidden;cursor:pointer;transition:.12s}
.card:hover,.card:focus-visible{border-color:var(--acc);transform:translateY(-2px)}
.card:focus-visible{outline:2px solid var(--acc);outline-offset:2px}
.card .img{display:block;width:100%;aspect-ratio:1;object-fit:cover;background:#0f1115}
.card .meta{padding:9px 11px}
.card .meta b{display:block;font-size:.92rem}
.card .meta span{color:var(--mut);font-size:.78rem;text-transform:capitalize}
.count{color:var(--mut);font-size:.85rem;margin:14px 2px}
dialog{background:var(--card);color:var(--fg);border:1px solid var(--line);border-radius:14px;max-width:680px;width:92%;padding:0}
dialog::backdrop{background:rgba(0,0,0,.6)}
.modal{padding:20px}
.modal h2{margin:0 0 2px}
.poses{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin:14px 0}
.poses.single{grid-template-columns:minmax(0,340px)}
.poses figure{margin:0;background:#0f1115;border-radius:10px;padding:8px;text-align:center}
.poses img{width:100%;aspect-ratio:1;object-fit:contain}
.poses figcaption{color:var(--mut);font-size:.75rem;margin-top:4px}
.chips{display:flex;gap:6px;flex-wrap:wrap;margin:8px 0}
.chip{background:#0f1115;border:1px solid var(--line);border-radius:999px;padding:3px 10px;font-size:.75rem;color:var(--mut);text-transform:capitalize}
ol{padding-left:18px}
.foot{border-top:1px solid var(--line);margin-top:16px;padding-top:12px;color:var(--mut);font-size:.85rem}
.x{position:absolute;top:10px;right:14px;background:0;border:0;color:var(--mut);font-size:1.4rem;cursor:pointer}
.promo{background:linear-gradient(90deg,#0f2417,#14171c);border:1px solid var(--line);border-radius:12px;padding:14px 16px;margin:0 0 18px;display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap}
.upgrade{margin:48px 0 0;border-top:1px solid var(--line);padding-top:28px}
.upgrade h2{font-size:1.25rem;margin:0 0 4px}
.upgrade .note{color:var(--mut);font-size:.88rem;margin:0 0 16px}
.upgrade .note b{color:var(--fg)}
.samples{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:14px}
.samples figure{margin:0;border:1px solid var(--line);border-radius:12px;padding:8px;text-align:center;
background-image:conic-gradient(#1b1e25 90deg,#0f1217 0 180deg,#1b1e25 0 270deg,#0f1217 0);background-size:16px 16px}
.samples img{width:100%;aspect-ratio:1;object-fit:contain}
.samples figcaption{color:var(--mut);font-size:.75rem;margin-top:4px;background:var(--bg);border-radius:6px;padding:2px 4px}
.samples .tag{color:var(--acc);font-weight:700}
.dock{position:fixed;left:0;right:0;bottom:0;z-index:20;display:flex;gap:12px;align-items:center;
max-width:1100px;margin:0 auto;padding:10px 20px calc(10px + env(safe-area-inset-bottom));
background:rgba(15,17,22,.92);backdrop-filter:blur(10px);border:1px solid var(--line);border-bottom:0;
border-radius:14px 14px 0 0;box-shadow:0 -10px 30px rgba(0,0,0,.45);
animation:dock-in .55s .5s cubic-bezier(.2,.8,.2,1) both}
@keyframes dock-in{from{transform:translateY(130%)}to{transform:translateY(0)}}
.dock-open{display:flex;gap:12px;align-items:center;flex:1;min-width:0;
background:0;border:0;padding:0;color:inherit;font:inherit;text-align:left;cursor:pointer}
.dock-open img{width:80px;height:80px;flex:none;object-fit:contain;border-radius:10px;padding:3px;
background-image:conic-gradient(#1b1e25 90deg,#0f1217 0 180deg,#1b1e25 0 270deg,#0f1217 0);background-size:12px 12px}
.dock-open:hover img,.dock-open:focus-visible img{outline:1px solid var(--acc)}
.dock-open:focus-visible{outline:2px solid var(--acc);outline-offset:3px;border-radius:10px}
.dock-copy{min-width:0}
.dock-copy b{display:block;font-size:.92rem}
.dock-copy b .tag{color:var(--acc)}
.dock-copy>span{display:block;color:var(--mut);font-size:.78rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dock .cta{flex:none;padding:9px 14px}
@media (max-width:560px){
.dock{gap:10px;padding:9px 12px calc(9px + env(safe-area-inset-bottom))}
.dock-open img{width:68px;height:68px}
.dock-copy>span,.dock-copy b .tag{display:none}
.dock-copy b{font-size:.86rem;line-height:1.25}
.dock .cta{padding:8px 11px;font-size:.85rem}
}
@media (prefers-reduced-motion:reduce){.dock{animation:none}}
</style>
</head>
<body>
<header>
<h1>Free Exercise Dataset — JSON + Images</h1>
<p class="sub">The free tier of <b>RepDB</b>: <b class="jscount">400</b> fitness exercises with flat illustrations, target muscles, equipment, MET, and instructions in English, German &amp; Spanish. Free for personal and commercial in-app use with attribution — see <a href="https://github.com/sergei-argutin/exercise-dataset/blob/main/LICENSE-DATA.md">LICENSE-DATA.md</a>. The full paid dataset keeps growing and adds high-res classic images, transparency and animations.</p>
<a class="cta" href="https://repdb.co/pricing?utm_source=huggingface">Get the full dataset →</a>
</header>
<div class="bar">
<input id="q" placeholder="Search exercises, muscles, equipment…" aria-label="Search exercises, muscles, equipment" />
<select id="body" aria-label="Filter by body part"><option value="">All body parts</option></select>
<select id="equip" aria-label="Filter by equipment"><option value="">All equipment</option></select>
</div>
<main>
<div class="promo">
<span>This is the <b>free tier</b><b><span class="jscount">400</span> exercises</b>, flat style, 512&nbsp;px, EN/DE/ES, attribution license. The full paid dataset keeps growing and ships classic white-background 1024&nbsp;px images, transparent backgrounds and looping animations.</span>
<a class="cta" href="https://repdb.co/pricing?utm_source=huggingface">See pricing →</a>
</div>
<div class="count" id="count"></div>
<div class="grid" id="grid"></div>
<section class="upgrade">
<h2>Upgrade samples — Standard tier preview</h2>
<p class="note"><b>Standard tier quality — evaluation only, see <a href="https://github.com/sergei-argutin/exercise-dataset/blob/main/LICENSE-DATA.md">LICENSE-DATA.md</a>.</b>
Looping, transparent-background exercise animations — the same clips shown on <a href="https://repdb.co/?utm_source=huggingface">repdb.co</a> (checkerboard shows the transparency). The Standard tier adds looping animations like these for most exercises → <a href="https://repdb.co/pricing?utm_source=huggingface">repdb.co/pricing</a>.</p>
<div class="samples">
<figure><img src="https://huggingface.co/datasets/RepDB/exercise-dataset/resolve/main/premium-samples/bent-over-db-row-start.webp" alt="Bent-over Dumbbell Row — classic start pose" loading="lazy"><figcaption>Bent-over DB Row · <span class="tag">start</span></figcaption></figure>
<figure><img src="https://huggingface.co/datasets/RepDB/exercise-dataset/resolve/main/premium-samples/bent-over-db-row-peak.webp" alt="Bent-over Dumbbell Row — classic peak pose" loading="lazy"><figcaption>Bent-over DB Row · <span class="tag">peak</span></figcaption></figure>
<figure><img src="https://huggingface.co/datasets/RepDB/exercise-dataset/resolve/main/premium-samples/bent-over-db-row.webp" alt="Bent-over Dumbbell Row — looping transparent animation" loading="lazy"><figcaption>Bent-over DB Row · <span class="tag">animation</span></figcaption></figure>
</div>
</section>
</main>
<aside class="dock" aria-label="Standard tier preview">
<button class="dock-open" id="premiumDock">
<img src="https://huggingface.co/datasets/RepDB/exercise-dataset/resolve/main/premium-samples/bent-over-db-row.webp" alt="Bent-over Dumbbell Row — looping transparent animation" />
<span class="dock-copy">
<b>Standard tier preview <span class="tag">— see the sample</span></b>
<span>Transparent looping animations and classic 1024 px images.</span>
</span>
</button>
<a class="cta" href="https://repdb.co/pricing?utm_source=huggingface">See pricing →</a>
</aside>
<dialog id="dlg"><button class="x" aria-label="Close" onclick="dlg.close()">×</button><div class="modal" id="modal"></div></dialog>
<script>
let DATA=[];
const ASSET_BASE='https://huggingface.co/datasets/RepDB/exercise-dataset/resolve/main/';
const PRICING_URL='https://repdb.co/pricing?utm_source=huggingface';
const grid=document.getElementById('grid'), q=document.getElementById('q'),
bodySel=document.getElementById('body'), equipSel=document.getElementById('equip'),
countEl=document.getElementById('count'), dlg=document.getElementById('dlg'), modal=document.getElementById('modal');
const cap=s=>(s||'').replace(/[-_]/g,' ');
fetch(ASSET_BASE+'exercises.json').then(r=>r.json()).then(d=>{
DATA=d.exercises;
document.querySelectorAll('.jscount').forEach(el=>el.textContent=DATA.length);
[...new Set(DATA.map(e=>e.body_part).filter(Boolean))].sort().forEach(v=>bodySel.add(new Option(cap(v),v)));
[...new Set(DATA.map(e=>e.equipment).filter(Boolean))].sort().forEach(v=>equipSel.add(new Option(cap(v),v)));
render();
}).catch(()=>{
grid.innerHTML='<p class="count">Could not load exercises.json — try reloading, or browse the <a href="https://github.com/sergei-argutin/exercise-dataset">repository files</a> directly.</p>';
});
dlg.onclick=ev=>{ if(ev.target===dlg) dlg.close(); };
document.getElementById('premiumDock').onclick=()=>{
const samples = [
['bent-over-db-row','Bent-over Dumbbell Row']
];
modal.innerHTML=`<section class="upgrade" style="margin:0;border:0;padding:0">
<h2>Premium samples - Standard tier preview</h2>
<p class="note"><b>Standard tier quality.</b> Transparent-background looping animations - the same kind of clips shipped in the paid Standard tier. The checkerboard shows the transparency.</p>
<div class="samples">${samples.map(([slug,name])=>`<figure><img src="${ASSET_BASE}premium-samples/${slug}.webp" alt="${name} - looping transparent animation"><figcaption>${name} · <span class="tag">animation</span></figcaption></figure>`).join('')}</div>
<div class="foot">The full paid dataset keeps growing - classic 1024 px images, transparency &amp; animations at <a href="${PRICING_URL}">repdb.co/pricing</a></div>
</section>`;
dlg.showModal();
};
function filtered(){
const t=q.value.toLowerCase(), b=bodySel.value, eq=equipSel.value;
return DATA.filter(e=>{
if(b&&e.body_part!==b) return false;
if(eq&&e.equipment!==eq) return false;
if(!t) return true;
return (e.name_en+' '+(e.body_part||'')+' '+(e.equipment||'')+' '+(e.primary_muscles||[]).join(' ')).toLowerCase().includes(t);
});
}
function flat(e){ return (e.images||{}).flat||{}; }
function asset(path){ return path ? ASSET_BASE+path : ''; }
function cardImg(e){ const f=flat(e); return asset(f.peak||f.main||f.start||''); }
function render(){
const list=filtered();
countEl.textContent=list.length+' of '+DATA.length+' exercises';
grid.innerHTML='';
list.forEach(e=>{
const c=document.createElement('div'); c.className='card';
c.tabIndex=0; c.setAttribute('role','button');
c.setAttribute('aria-label','Show details for '+e.name_en);
c.innerHTML=`<img class="img" loading="lazy" src="${cardImg(e)}" alt="">
<div class="meta"><b>${e.name_en}</b><span>${[e.body_part,e.equipment].filter(Boolean).map(cap).join(' · ')}</span></div>`;
c.onclick=()=>open_(e);
c.onkeydown=ev=>{ if(ev.key==='Enter'||ev.key===' '){ ev.preventDefault(); open_(e); } };
grid.appendChild(c);
});
}
function poses(e){
const f=flat(e);
if(f.start&&f.peak) return `<div class="poses">
<figure><img src="${asset(f.start)}" alt="${e.name_en} start"><figcaption>Start</figcaption></figure>
<figure><img src="${asset(f.peak)}" alt="${e.name_en} peak"><figcaption>Peak</figcaption></figure>
</div>`;
const u=f.main||f.start||f.peak;
return u?`<div class="poses single">
<figure><img src="${asset(u)}" alt="${e.name_en}"></figure>
</div>`:'';
}
function open_(e){
const chips=[...(e.primary_muscles||[]),...(e.tags||[])].map(m=>`<span class="chip">${cap(m)}</span>`).join('');
const steps=(e.instructions_en||[]).map(s=>`<li>${s}</li>`).join('');
modal.innerHTML=`<h2>${e.name_en}</h2>
<div style="color:var(--mut)">${cap(e.difficulty)} · ${cap(e.mechanic)} · ${cap(e.category)}${e.met?' · MET '+e.met:''}</div>
${poses(e)}
<p>${e.description_en||''}</p>
<div class="chips">${chips}</div>
${steps?`<ol>${steps}</ol>`:''}
<div class="foot">German &amp; Spanish translations are in the JSON. The full paid dataset keeps growing — classic 1024&nbsp;px images, transparency &amp; animations at <a href="https://repdb.co">repdb.co →</a></div>`;
dlg.showModal();
}
q.oninput=bodySel.onchange=equipSel.onchange=render;
</script>
</body>
</html>