| <!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 & 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 px, EN/DE/ES, attribution license. The full paid dataset keeps growing and ships classic white-background 1024 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 & 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 & Spanish translations are in the JSON. The full paid dataset keeps growing — classic 1024 px images, transparency & animations at <a href="https://repdb.co">repdb.co →</a></div>`; |
| dlg.showModal(); |
| } |
| q.oninput=bodySel.onchange=equipSel.onchange=render; |
| </script> |
| </body> |
| </html> |
|
|