{"id":18133,"date":"2026-09-16T13:03:35","date_gmt":"2026-09-16T13:03:35","guid":{"rendered":"https:\/\/blackbeltwhitehat.com\/?page_id=18133"},"modified":"2026-09-18T10:03:18","modified_gmt":"2026-09-18T10:03:18","slug":"diretorio-de-exercicios","status":"publish","type":"page","link":"https:\/\/blackbeltwhitehat.com\/pt\/diretorio-de-exercicios\/","title":{"rendered":"Diret\u00f3rio de exerc\u00edcios de academia"},"content":{"rendered":"\n<!-- Exercise Directory \u2014 paste this whole thing into a Gutenberg Custom HTML block -->\n<!-- Data source: Free Exercise DB, public domain (Unlicense). ~800 exercises fetched at page load. -->\n\n<link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin=\"\">\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700&amp;display=swap\" rel=\"stylesheet\">\n\n<style>\n\/* Let the exercise + technique directories fill more of your content area *\/\n.exdir .wrap,\n.tdir .wrap {\n    max-width: none;        \/* was 1240px *\/\n    padding-left: 4px;\n    padding-right: 4px;\n}\n\n  .exdir {\n    --bg: #FFFFFF;\n    --panel: #F8F6F1;\n    --card: #FFFFFF;\n    --ink: #0F0F0F;\n    --ink-2: #3A3A3A;\n    --meta: #767676;\n    --rule: #E4E1D8;\n    --rule-strong: #B8B3A6;\n    --accent: #B33A2F;\n    --accent-soft: rgba(179, 58, 47, 0.08);\n    --tag-bg: #F0EBE1;\n    --tag-ink: #5A4E3C;\n    --focus: #B33A2F;\n    --shadow: 0 1px 0 rgba(15,15,15,0.04);\n  }\n  @media (prefers-color-scheme: dark) {\n    .exdir:not([data-theme=\"light\"]) {\n      --bg: #14130F;\n      --panel: #1C1B17;\n      --card: #1C1B17;\n      --ink: #EDEAE1;\n      --ink-2: #C4C0B4;\n      --meta: #8A8578;\n      --rule: #2E2C26;\n      --rule-strong: #423F37;\n      --accent: #E86155;\n      --accent-soft: rgba(232, 97, 85, 0.14);\n      --tag-bg: #2A2822;\n      --tag-ink: #C4B99E;\n      --focus: #E86155;\n      --shadow: 0 1px 0 rgba(0,0,0,0.4);\n    }\n  }\n  .exdir[data-theme=\"dark\"] {\n    --bg: #14130F;\n    --panel: #1C1B17;\n    --card: #1C1B17;\n    --ink: #EDEAE1;\n    --ink-2: #C4C0B4;\n    --meta: #8A8578;\n    --rule: #2E2C26;\n    --rule-strong: #423F37;\n    --accent: #E86155;\n    --accent-soft: rgba(232, 97, 85, 0.14);\n    --tag-bg: #2A2822;\n    --tag-ink: #C4B99E;\n    --focus: #E86155;\n    --shadow: 0 1px 0 rgba(0,0,0,0.4);\n  }\n\n  .exdir, .exdir *, .exdir *::before, .exdir *::after { box-sizing: border-box; }\n  \n  .exdir {\n    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n    font-size: 15px;\n    line-height: 1.5;\n    color: var(--ink);\n    background: var(--bg);\n    -webkit-font-smoothing: antialiased;\n    text-rendering: optimizeLegibility;\n  }\n  .exdir img { max-width: 100%; height: auto; display: block; }\n  .exdir button { font: inherit; color: inherit; cursor: pointer; background: none; border: none; padding: 0; }\n\n  .exdir :focus-visible {\n    outline: 2px solid var(--focus);\n    outline-offset: 2px;\n  }\n\n  .exdir .wrap {\n    max-width: 1240px;\n    margin: 0 auto;\n    padding: 2px 4px 8px;\n  }\n  @media (max-width: 640px) {\n    .wrap { padding: 2px 6px 6px; }\n  }\n\n  \/* Header *\/\n  .exdir header.top {\n    display: flex;\n    align-items: flex-end;\n    justify-content: space-between;\n    gap: 24px;\n    padding-bottom: 20px;\n    border-bottom: 1px solid var(--rule-strong);\n    margin-bottom: 24px;\n  }\n  .exdir header.top h1 {\n    font-size: 32px;\n    font-weight: 700;\n    letter-spacing: -0.02em;\n    margin: 0 0 4px;\n    line-height: 1.1;\n  }\n  .exdir header.top .subtitle {\n    font-size: 15px;\n    color: var(--meta);\n    margin: 0;\n    max-width: 44ch;\n  }\n  .exdir header.top .count {\n    font-size: 13px;\n    color: var(--meta);\n    font-variant-numeric: tabular-nums;\n    white-space: nowrap;\n    padding-bottom: 4px;\n  }\n  .exdir header.top .count strong {\n    font-weight: 600;\n    color: var(--ink);\n  }\n  @media (max-width: 640px) {\n    header.top { flex-direction: column; align-items: flex-start; gap: 8px; }\n    header.top h1 { font-size: 26px; }\n  }\n\n  \/* Search + filters *\/\n  .exdir .controls {\n    display: grid;\n    grid-template-columns: 1fr;\n    gap: 20px;\n    margin-bottom: 32px;\n  }\n  .exdir .search-row {\n    position: relative;\n  }\n  .exdir .search-row input {\n    width: 100%;\n    padding: 12px 14px 12px 40px;\n    font-size: 15px;\n    font-family: inherit;\n    color: var(--ink);\n    background: var(--card);\n    border: 1px solid var(--rule);\n    border-radius: 6px;\n    transition: border-color 0.15s, box-shadow 0.15s;\n  }\n  .exdir .search-row input:focus {\n    outline: none;\n    border-color: var(--accent);\n    box-shadow: 0 0 0 3px var(--accent-soft);\n  }\n  .search-row input::placeholder { color: var(--meta); }\n  .exdir .search-row .search-icon {\n    position: absolute;\n    left: 14px;\n    top: 50%;\n    transform: translateY(-50%);\n    color: var(--meta);\n    pointer-events: none;\n    width: 16px;\n    height: 16px;\n  }\n\n  .exdir .filter-groups {\n    display: grid;\n    grid-template-columns: 1fr;\n    gap: 16px;\n  }\n  .exdir .filter-group {\n    display: grid;\n    grid-template-columns: 90px 1fr;\n    gap: 12px;\n    align-items: baseline;\n  }\n  .exdir .filter-group h3 {\n    font-size: 13px;\n    font-weight: 600;\n    color: var(--meta);\n    margin: 0;\n    padding-top: 6px;\n  }\n  .exdir .chips {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 6px;\n  }\n  .exdir .chip {\n    background: transparent;\n    border: 1px solid var(--rule);\n    color: var(--ink-2);\n    padding: 5px 11px;\n    border-radius: 4px;\n    font-size: 13px;\n    font-weight: 500;\n    line-height: 1.4;\n    transition: all 0.12s;\n    text-transform: capitalize;\n  }\n  .chip:hover { border-color: var(--rule-strong); color: var(--ink); }\n  .exdir .chip.active {\n    background: var(--ink);\n    color: var(--bg);\n    border-color: var(--ink);\n  }\n  .exdir[data-theme=\"dark\"] .chip.active,\n  .exdir:not([data-theme=\"light\"]) .chip.active {\n    background: var(--ink);\n    color: var(--bg);\n  }\n  @media (max-width: 640px) {\n    .filter-group { grid-template-columns: 1fr; gap: 4px; }\n    .filter-group h3 { padding-top: 0; }\n  }\n\n  .exdir .toolbar {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    gap: 12px;\n    margin-bottom: 20px;\n    padding-top: 16px;\n    border-top: 1px solid var(--rule);\n    font-size: 13px;\n    color: var(--meta);\n  }\n  .exdir .clear-btn {\n    background: transparent;\n    border: none;\n    padding: 4px 8px;\n    margin: -4px -8px;\n    border-radius: 4px;\n    color: var(--accent);\n    font-weight: 500;\n    font-size: 13px;\n  }\n  .clear-btn:hover { background: var(--accent-soft); }\n  .clear-btn[hidden] { display: none; }\n\n  \/* Grid *\/\n  .exdir .grid {\n    display: grid;\n    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));\n    gap: 16px;\n  }\n\n  .exdir .card {\n    background: var(--card);\n    border: 1px solid var(--rule);\n    border-radius: 6px;\n    overflow: hidden;\n    cursor: pointer;\n    transition: border-color 0.15s, transform 0.15s;\n    text-align: left;\n    padding: 0;\n    display: flex;\n    flex-direction: column;\n    font: inherit;\n    color: inherit;\n    width: 100%;\n  }\n  .exdir .card:hover {\n    border-color: var(--rule-strong);\n  }\n  .card:hover .card-name { color: var(--accent); }\n  .exdir .card:focus-visible {\n    outline-offset: -2px;\n  }\n\n  .exdir .card-img {\n    position: relative;\n    aspect-ratio: 4 \/ 3;\n    background: var(--panel);\n    overflow: hidden;\n    border-bottom: 1px solid var(--rule);\n  }\n  .exdir .card-img img {\n    position: absolute;\n    inset: 0;\n    width: 100%;\n    height: 100%;\n    object-fit: cover;\n  }\n  .exdir .card-img .frame-b {\n    animation: crossfade 1.8s ease-in-out infinite;\n  }\n  @keyframes crossfade {\n    0%, 30%   { opacity: 0; }\n    50%, 80%  { opacity: 1; }\n    100%      { opacity: 0; }\n  }\n  @media (prefers-reduced-motion: reduce) {\n    .card-img .frame-b { animation: none; opacity: 0.5; }\n  }\n\n  .exdir .card-body {\n    padding: 12px 14px 14px;\n    display: flex;\n    flex-direction: column;\n    gap: 6px;\n  }\n  .exdir .card-name {\n    font-size: 15px;\n    font-weight: 600;\n    color: var(--ink);\n    line-height: 1.3;\n    letter-spacing: -0.005em;\n    transition: color 0.15s;\n  }\n  .exdir .card-tags {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 4px;\n    align-items: center;\n  }\n  .exdir .tag {\n    background: var(--tag-bg);\n    color: var(--tag-ink);\n    font-size: 11.5px;\n    font-weight: 500;\n    padding: 2px 7px;\n    border-radius: 3px;\n    line-height: 1.5;\n    text-transform: capitalize;\n  }\n  .exdir .tag.muscle {\n    background: transparent;\n    color: var(--accent);\n    padding: 2px 0;\n    font-weight: 600;\n    font-size: 11.5px;\n  }\n\n  \/* Empty state *\/\n  .exdir .empty {\n    text-align: center;\n    padding: 60px 20px;\n    color: var(--meta);\n  }\n  .empty p { margin: 0 0 12px; font-size: 15px; }\n  .exdir .empty button {\n    background: var(--ink);\n    color: var(--bg);\n    border: none;\n    padding: 8px 16px;\n    border-radius: 4px;\n    font-size: 14px;\n    font-weight: 500;\n  }\n\n  \/* Footer *\/\n  .exdir footer {\n    margin-top: 60px;\n    padding-top: 20px;\n    border-top: 1px solid var(--rule);\n    font-size: 12.5px;\n    color: var(--meta);\n    line-height: 1.6;\n  }\n  footer a { color: var(--ink-2); }\n\n  \/* Modal *\/\n  .exdir .modal {\n    position: fixed;\n    inset: 0;\n    background: rgba(15, 15, 15, 0.5);\n    display: flex;\n    align-items: flex-start;\n    justify-content: center;\n    padding: 40px 20px;\n    z-index: 100;\n    opacity: 0;\n    pointer-events: none;\n    transition: opacity 0.15s;\n    overflow-y: auto;\n  }\n  .exdir .modal.open {\n    opacity: 1;\n    pointer-events: auto;\n  }\n  .exdir .modal-panel {\n    background: var(--card);\n    border-radius: 8px;\n    max-width: 720px;\n    width: 100%;\n    max-height: none;\n    display: flex;\n    flex-direction: column;\n    border: 1px solid var(--rule-strong);\n    box-shadow: 0 20px 60px rgba(0,0,0,0.15);\n  }\n  @media (max-width: 640px) {\n    .modal { padding: 12px; }\n  }\n  .exdir .modal-header {\n    display: flex;\n    justify-content: space-between;\n    align-items: flex-start;\n    padding: 20px 24px 16px;\n    border-bottom: 1px solid var(--rule);\n    gap: 16px;\n  }\n  .exdir .modal-header h2 {\n    font-size: 22px;\n    font-weight: 700;\n    letter-spacing: -0.01em;\n    margin: 0;\n    line-height: 1.2;\n  }\n  .exdir .modal-close {\n    background: transparent;\n    border: 1px solid var(--rule);\n    width: 32px;\n    height: 32px;\n    border-radius: 4px;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    color: var(--ink-2);\n    flex-shrink: 0;\n  }\n  .modal-close:hover { border-color: var(--rule-strong); color: var(--ink); }\n  .exdir .modal-body {\n    padding: 20px 24px 24px;\n    overflow-y: auto;\n  }\n  .exdir .modal-media {\n    aspect-ratio: 16 \/ 10;\n    background: var(--panel);\n    border-radius: 6px;\n    position: relative;\n    overflow: hidden;\n    margin-bottom: 20px;\n    border: 1px solid var(--rule);\n  }\n  .exdir .modal-media img {\n    position: absolute;\n    inset: 0;\n    width: 100%;\n    height: 100%;\n    object-fit: contain;\n  }\n  .exdir .modal-media .frame-b {\n    animation: crossfade 1.8s ease-in-out infinite;\n  }\n  .exdir .modal-meta {\n    display: grid;\n    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));\n    gap: 16px;\n    padding: 16px 0;\n    border-top: 1px solid var(--rule);\n    border-bottom: 1px solid var(--rule);\n    margin-bottom: 20px;\n  }\n  .exdir .modal-meta dt {\n    font-size: 12px;\n    color: var(--meta);\n    margin: 0 0 3px;\n    font-weight: 500;\n  }\n  .exdir .modal-meta dd {\n    font-size: 14px;\n    color: var(--ink);\n    margin: 0;\n    font-weight: 500;\n    text-transform: capitalize;\n  }\n  .exdir .modal-body h3 {\n    font-size: 14px;\n    font-weight: 600;\n    margin: 20px 0 10px;\n    color: var(--ink);\n  }\n  .modal-body h3:first-of-type { margin-top: 0; }\n  .exdir .modal-body ol {\n    padding-left: 22px;\n    margin: 0;\n    color: var(--ink-2);\n  }\n  .exdir .modal-body ol li {\n    margin-bottom: 10px;\n    line-height: 1.55;\n  }\n  .exdir .modal-body ol li::marker {\n    color: var(--accent);\n    font-weight: 600;\n  }\n  .exdir .muscle-list {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 6px;\n    margin: 0;\n    padding: 0;\n    list-style: none;\n  }\n  .exdir .muscle-list li {\n    background: var(--tag-bg);\n    color: var(--tag-ink);\n    padding: 3px 9px;\n    border-radius: 3px;\n    font-size: 13px;\n    text-transform: capitalize;\n    font-weight: 500;\n  }\n  .exdir .muscle-list li.primary {\n    background: var(--accent);\n    color: white;\n  }\n\n<\/style>\n\n<div class=\"exdir\">\n<div class=\"wrap\">\n  <header class=\"top\">\n    <div>\n      <h1>Exercise Directory<\/h1>\n      <p class=\"subtitle\">Filter by muscle group, equipment, or category. Tap a card for coaching notes and full instructions.<\/p>\n    <\/div>\n    <div class=\"count\"><strong id=\"exdir-visible-count\">0<\/strong> of <span id=\"exdir-total-count\">0<\/span> exercises<\/div>\n  <\/header>\n\n  <div class=\"controls\">\n    <div class=\"search-row\">\n      <svg class=\"search-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"11\" cy=\"11\" r=\"8\"><\/circle><path d=\"m21 21-4.3-4.3\"><\/path><\/svg>\n      <input type=\"search\" id=\"exdir-search\" placeholder=\"Search \u2014 e.g. squat, dumbbell, hamstring\" autocomplete=\"off\">\n    <\/div>\n    <div class=\"filter-groups\" id=\"exdir-filter-groups\"><\/div>\n  <\/div>\n\n  <div class=\"toolbar\">\n    <div id=\"exdir-active-summary\">Showing all exercises<\/div>\n    <button class=\"clear-btn\" id=\"exdir-clear-btn\" hidden=\"\">Clear filters<\/button>\n  <\/div>\n\n  <main class=\"grid\" id=\"exdir-grid\" role=\"list\"><\/main>\n\n  <div class=\"empty\" id=\"exdir-empty\" hidden=\"\">\n    <p>No exercises match these filters.<\/p>\n    <button id=\"exdir-empty-clear\">Clear filters<\/button>\n  <\/div>\n\n  <footer>\n    <p>Data: <a href=\"https:\/\/github.com\/yuhonas\/free-exercise-db\" target=\"_blank\" rel=\"noopener\">Free Exercise DB<\/a> \u2014 public domain (Unlicense), 800+ exercises. Frames alternate between the start and peak of each rep.<\/p>\n  <\/footer>\n<\/div>\n\n<div class=\"modal\" id=\"exdir-modal\" hidden=\"\" aria-hidden=\"true\" role=\"dialog\" aria-labelledby=\"exdir-modal-title\" aria-modal=\"true\">\n  <div class=\"modal-panel\">\n    <div class=\"modal-header\">\n      <h2 id=\"exdir-modal-title\"><\/h2>\n      <button class=\"modal-close\" id=\"exdir-modal-close\" aria-label=\"Close\">\n        <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M18 6 6 18\"><\/path><path d=\"m6 6 12 12\"><\/path><\/svg>\n      <\/button>\n    <\/div>\n    <div class=\"modal-body\" id=\"exdir-modal-body\"><\/div>\n  <\/div>\n<\/div>\n<\/div>\n\n<script>\n(function() {\n\n\/\/ Source: Free Exercise DB (public domain \/ Unlicense)\n\/\/ Fetches full 800+ exercise dataset from GitHub raw on page load.\nconst DATA_URL = 'https:\/\/raw.githubusercontent.com\/yuhonas\/free-exercise-db\/main\/dist\/exercises.json';\nconst IMAGE_BASE = 'https:\/\/raw.githubusercontent.com\/yuhonas\/free-exercise-db\/main\/exercises\/';\n\nlet EXERCISES = [];\nconst IMAGES = new Proxy({}, {\n  get(_, path) {\n    return typeof path === 'string' ? IMAGE_BASE + path : undefined;\n  }\n});\n\nconst FILTERS = [\n  { key: 'primary',   label: 'Muscle' },\n  { key: 'equipment', label: 'Kit' },\n  { key: 'category',  label: 'Type' },\n  { key: 'level',     label: 'Level' }\n];\n\nconst state = {\n  search: '',\n  active: { primary: null, equipment: null, category: null, level: null }\n};\n\n\/\/ -----------------------------------------------------------\n\/\/ Init\n\/\/ -----------------------------------------------------------\nconst grid = document.getElementById('exdir-grid');\nconst empty = document.getElementById('exdir-empty');\nconst searchInput = document.getElementById('exdir-search');\nconst filterGroups = document.getElementById('exdir-filter-groups');\nconst visibleCountEl = document.getElementById('exdir-visible-count');\nconst totalCountEl = document.getElementById('exdir-total-count');\nconst activeSummary = document.getElementById('exdir-active-summary');\nconst clearBtn = document.getElementById('exdir-clear-btn');\nconst emptyClear = document.getElementById('exdir-empty-clear');\nconst modal = document.getElementById('exdir-modal');\nconst modalTitle = document.getElementById('exdir-modal-title');\nconst modalBody = document.getElementById('exdir-modal-body');\nconst modalClose = document.getElementById('exdir-modal-close');\n\n\/\/ Compute options for each filter\nfunction optionsFor(key) {\n  const set = new Set();\n  for (const ex of EXERCISES) {\n    if (key === 'primary') {\n      (ex.primaryMuscles || []).forEach(m => set.add(m));\n    } else if (ex[key]) {\n      set.add(ex[key]);\n    }\n  }\n  return [...set].sort();\n}\n\n\/\/ Render filter chips\nfunction renderFilters() {\n  filterGroups.innerHTML = '';\n  for (const f of FILTERS) {\n    const opts = optionsFor(f.key);\n    if (!opts.length) continue;\n    const wrap = document.createElement('div');\n    wrap.className = 'filter-group';\n    wrap.dataset.key = f.key;\n    wrap.innerHTML = `<h3>${f.label}<\/h3><div class=\"chips\"><\/div>`;\n    const chipsContainer = wrap.querySelector('.chips');\n    for (const opt of opts) {\n      const btn = document.createElement('button');\n      btn.className = 'chip';\n      btn.type = 'button';\n      btn.textContent = opt;\n      btn.dataset.key = f.key;\n      btn.dataset.value = opt;\n      btn.addEventListener('click', () => {\n        state.active[f.key] = state.active[f.key] === opt ? null : opt;\n        update();\n      });\n      chipsContainer.appendChild(btn);\n    }\n    filterGroups.appendChild(wrap);\n  }\n}\n\n\/\/ Filter logic\nfunction matches(ex) {\n  if (state.search) {\n    const q = state.search.toLowerCase();\n    const hay = (ex.name + ' ' + (ex.primaryMuscles || []).join(' ') + ' ' + (ex.equipment || '')).toLowerCase();\n    if (!hay.includes(q)) return false;\n  }\n  for (const key of Object.keys(state.active)) {\n    const val = state.active[key];\n    if (!val) continue;\n    if (key === 'primary') {\n      if (!(ex.primaryMuscles || []).includes(val)) return false;\n    } else {\n      if (ex[key] !== val) return false;\n    }\n  }\n  return true;\n}\n\n\/\/ Render grid\nfunction renderGrid() {\n  const filtered = EXERCISES.filter(matches);\n  visibleCountEl.textContent = filtered.length;\n\n  if (filtered.length === 0) {\n    grid.hidden = true;\n    empty.hidden = false;\n    return;\n  }\n  grid.hidden = false;\n  empty.hidden = true;\n\n  const frag = document.createDocumentFragment();\n  for (const ex of filtered) {\n    const card = document.createElement('button');\n    card.className = 'card';\n    card.type = 'button';\n    card.setAttribute('role', 'listitem');\n    card.addEventListener('click', () => openModal(ex));\n\n    const imgs = (ex.images || []).map(p => IMAGES[p]).filter(Boolean);\n    const [imgA, imgB] = imgs.length >= 2 ? imgs : [imgs[0], imgs[0]];\n\n    const primary = (ex.primaryMuscles || [])[0] || '';\n    const equip = ex.equipment && ex.equipment !== 'body only' ? ex.equipment : (ex.equipment === 'body only' ? 'bodyweight' : '');\n\n    card.innerHTML = `\n      <div class=\"card-img\">\n        ${imgA ? `<img decoding=\"async\" loading=\"lazy\" src=\"${imgA}\" alt=\"\">` : ''}\n        ${imgB ? `<img decoding=\"async\" loading=\"lazy\" class=\"frame-b\" src=\"${imgB}\" alt=\"\">` : ''}\n      <\/div>\n      <div class=\"card-body\">\n        <div class=\"card-name\">${escapeHtml(ex.name)}<\/div>\n        <div class=\"card-tags\">\n          ${primary ? `<span class=\"tag muscle\">${escapeHtml(primary)}<\/span>` : ''}\n          ${equip ? `<span class=\"tag\">${escapeHtml(equip)}<\/span>` : ''}\n        <\/div>\n      <\/div>\n    `;\n    frag.appendChild(card);\n  }\n  grid.innerHTML = '';\n  grid.appendChild(frag);\n}\n\nfunction renderChipStates() {\n  document.querySelectorAll('.chip').forEach(chip => {\n    const key = chip.dataset.key;\n    const val = chip.dataset.value;\n    chip.classList.toggle('active', state.active[key] === val);\n  });\n}\n\nfunction renderSummary() {\n  const parts = [];\n  for (const f of FILTERS) {\n    if (state.active[f.key]) parts.push(state.active[f.key]);\n  }\n  if (state.search) parts.push('\"' + state.search + '\"');\n  const anyActive = parts.length > 0;\n  activeSummary.textContent = anyActive\n    ? 'Filtered: ' + parts.join(' \u00b7 ')\n    : 'Showing all exercises';\n  clearBtn.hidden = !anyActive;\n}\n\nfunction update() {\n  renderChipStates();\n  renderSummary();\n  renderGrid();\n}\n\nfunction clearAll() {\n  state.search = '';\n  searchInput.value = '';\n  for (const key of Object.keys(state.active)) state.active[key] = null;\n  update();\n}\n\n\/\/ Modal\nfunction openModal(ex) {\n  modalTitle.textContent = ex.name;\n  const imgs = (ex.images || []).map(p => IMAGES[p]).filter(Boolean);\n  const [imgA, imgB] = imgs.length >= 2 ? imgs : [imgs[0], imgs[0]];\n\n  const primaryMuscles = (ex.primaryMuscles || []).map(m => `<li class=\"primary\">${escapeHtml(m)}<\/li>`).join('');\n  const secondaryMuscles = (ex.secondaryMuscles || []).map(m => `<li>${escapeHtml(m)}<\/li>`).join('');\n  const allMuscles = primaryMuscles + secondaryMuscles;\n\n  const instructions = (ex.instructions || []).map(i => `<li>${escapeHtml(i)}<\/li>`).join('');\n\n  const meta = [\n    { l: 'Equipment', v: ex.equipment || '\u2014' },\n    { l: 'Category', v: ex.category || '\u2014' },\n    { l: 'Level', v: ex.level || '\u2014' },\n    { l: 'Force', v: ex.force || '\u2014' },\n    { l: 'Mechanic', v: ex.mechanic || '\u2014' }\n  ].map(m => `<div><dt>${m.l}<\/dt><dd>${escapeHtml(String(m.v))}<\/dd><\/div>`).join('');\n\n  modalBody.innerHTML = `\n    <div class=\"modal-media\">\n      ${imgA ? `<img decoding=\"async\" src=\"${imgA}\" alt=\"\">` : ''}\n      ${imgB ? `<img decoding=\"async\" class=\"frame-b\" src=\"${imgB}\" alt=\"\">` : ''}\n    <\/div>\n    <dl class=\"modal-meta\">${meta}<\/dl>\n    ${allMuscles ? `<h3>Muscles worked<\/h3><ul class=\"muscle-list\">${allMuscles}<\/ul>` : ''}\n    ${instructions ? `<h3>Instructions<\/h3><ol>${instructions}<\/ol>` : ''}\n  `;\n\n  modal.hidden = false;\n  requestAnimationFrame(() => modal.classList.add('open'));\n  modal.setAttribute('aria-hidden', 'false');\n  modalClose.focus();\n  document.body.style.overflow = 'hidden';\n}\n\nfunction closeModal() {\n  modal.classList.remove('open');\n  modal.setAttribute('aria-hidden', 'true');\n  document.body.style.overflow = '';\n  setTimeout(() => { modal.hidden = true; }, 150);\n}\n\n\/\/ Utils\nfunction escapeHtml(s) {\n  return String(s).replace(\/[&<>\"']\/g, c => ({\n    '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;'\n  })[c]);\n}\n\n\/\/ Event handlers\nsearchInput.addEventListener('input', e => {\n  state.search = e.target.value.trim();\n  update();\n});\nclearBtn.addEventListener('click', clearAll);\nemptyClear.addEventListener('click', clearAll);\nmodalClose.addEventListener('click', closeModal);\nmodal.addEventListener('click', e => { if (e.target === modal) closeModal(); });\ndocument.addEventListener('keydown', e => {\n  if (e.key === 'Escape' && !modal.hidden) closeModal();\n});\n\n\/\/ Init: fetch dataset then render\nasync function init() {\n  activeSummary.textContent = 'Loading exercises\u2026';\n  try {\n    const res = await fetch(DATA_URL);\n    if (!res.ok) throw new Error('HTTP ' + res.status);\n    EXERCISES = await res.json();\n  } catch (err) {\n    activeSummary.textContent = 'Could not load exercises. Check your connection and reload.';\n    console.error(err);\n    return;\n  }\n  totalCountEl.textContent = EXERCISES.length;\n  renderFilters();\n  update();\n}\ninit();\n\n})();\n<\/script>\n","protected":false},"excerpt":{"rendered":"<p>Filtre o Diret\u00f3rio de Exerc\u00edcios por grupo muscular, equipamento ou categoria. Toque em um cart\u00e3o para ver notas de treinamento e instru\u00e7\u00f5es completas. 0 de 0 exerc\u00edcios Exibindo todos os exerc\u00edcios Limpar filtros Nenhum exerc\u00edcio corresponde a estes filtros. Limpar filtros Dados: Banco de Dados de Exerc\u00edcios Gratuito \u2014 dom\u00ednio p\u00fablico (sem licen\u00e7a), mais de 800 exerc\u00edcios. Os quadros alternam entre o in\u00edcio e o pico de cada repeti\u00e7\u00e3o.<\/p>","protected":false},"author":41980142,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","_wpcom_ai_launchpad_about_page":false,"_wpcom_ai_launchpad_gallery_page":false,"_wpcom_ai_launchpad_contact_page":false,"_wpcom_ai_launchpad_events_page":false,"_wpcom_ai_launchpad_video_page":false,"_wpcom_ai_launchpad_portfolio_piece":false,"footnotes":""},"class_list":["post-18133","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Gym Exercise Directory - Fitness &amp; MMA Blog - BlackBeltWhiteHat.com<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blackbeltwhitehat.com\/pt\/diretorio-de-exercicios\/\" \/>\n<meta property=\"og:locale\" content=\"pt_PT\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Gym Exercise Directory - Fitness &amp; MMA Blog - BlackBeltWhiteHat.com\" \/>\n<meta property=\"og:description\" content=\"Exercise Directory Filter by muscle group, equipment, or category. Tap a card for coaching notes and full instructions. 0 of 0 exercises Showing all exercises Clear filters No exercises match these filters. Clear filters Data: Free Exercise DB \u2014 public domain (Unlicense), 800+ exercises. Frames alternate between the start and peak of each rep.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blackbeltwhitehat.com\/pt\/diretorio-de-exercicios\/\" \/>\n<meta property=\"og:site_name\" content=\"Fitness &amp; MMA Blog - BlackBeltWhiteHat.com\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/BlackBeltWhiteHat\/\" \/>\n<meta property=\"article:modified_time\" content=\"2026-09-18T10:03:18+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:site\" content=\"@MMATraining1980\" \/>\n<meta name=\"twitter:label1\" content=\"Tempo estimado de leitura\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minuto\" \/>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Gym Exercise Directory - Fitness &amp; MMA Blog - BlackBeltWhiteHat.com","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blackbeltwhitehat.com\/pt\/diretorio-de-exercicios\/","og_locale":"pt_PT","og_type":"article","og_title":"Gym Exercise Directory - Fitness &amp; MMA Blog - BlackBeltWhiteHat.com","og_description":"Exercise Directory Filter by muscle group, equipment, or category. Tap a card for coaching notes and full instructions. 0 of 0 exercises Showing all exercises Clear filters No exercises match these filters. Clear filters Data: Free Exercise DB \u2014 public domain (Unlicense), 800+ exercises. Frames alternate between the start and peak of each rep.","og_url":"https:\/\/blackbeltwhitehat.com\/pt\/diretorio-de-exercicios\/","og_site_name":"Fitness &amp; MMA Blog - BlackBeltWhiteHat.com","article_publisher":"https:\/\/www.facebook.com\/BlackBeltWhiteHat\/","article_modified_time":"2026-09-18T10:03:18+00:00","twitter_card":"summary_large_image","twitter_site":"@MMATraining1980","twitter_misc":{"Tempo estimado de leitura":"1 minuto"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/blackbeltwhitehat.com\/exercise-directory\/","url":"https:\/\/blackbeltwhitehat.com\/exercise-directory\/","name":"Gym Exercise Directory - Fitness &amp; MMA Blog - BlackBeltWhiteHat.com","isPartOf":{"@id":"https:\/\/blackbeltwhitehat.com\/en\/#website"},"datePublished":"2026-09-16T13:03:35+00:00","dateModified":"2026-09-18T10:03:18+00:00","breadcrumb":{"@id":"https:\/\/blackbeltwhitehat.com\/exercise-directory\/#breadcrumb"},"inLanguage":"pt-PT","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blackbeltwhitehat.com\/exercise-directory\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/blackbeltwhitehat.com\/exercise-directory\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blackbeltwhitehat.com\/"},{"@type":"ListItem","position":2,"name":"Gym Exercise Directory"}]},{"@type":"WebSite","@id":"https:\/\/blackbeltwhitehat.com\/en\/#website","url":"https:\/\/blackbeltwhitehat.com\/en\/","name":"Blog de Fitness e MMA - BlackBeltWhiteHat.com","description":"Blog de fitness, MMA e nutri\u00e7\u00e3o do Reino Unido","publisher":{"@id":"https:\/\/blackbeltwhitehat.com\/en\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blackbeltwhitehat.com\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"pt-PT"},{"@type":"Organization","@id":"https:\/\/blackbeltwhitehat.com\/en\/#organization","name":"Blog de Fitness e MMA - BlackBeltWhiteHat.com","url":"https:\/\/blackbeltwhitehat.com\/en\/","logo":{"@type":"ImageObject","inLanguage":"pt-PT","@id":"https:\/\/blackbeltwhitehat.com\/en\/#\/schema\/logo\/image\/","url":"https:\/\/blackbeltwhitehat.com\/wp-content\/uploads\/2019\/06\/cropped-mmabloglogodis-copy.png","contentUrl":"https:\/\/blackbeltwhitehat.com\/wp-content\/uploads\/2019\/06\/cropped-mmabloglogodis-copy.png","width":352,"height":352,"caption":"Fitness & MMA Blog - BlackBeltWhiteHat.com"},"image":{"@id":"https:\/\/blackbeltwhitehat.com\/en\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/BlackBeltWhiteHat\/","https:\/\/x.com\/MMATraining1980"]}]}},"jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/P2Sx3t-4It","jetpack-related-posts":[{"id":18137,"url":"https:\/\/blackbeltwhitehat.com\/pt\/diretorio-de-exercicios\/tecnicas-essenciais-de-mma-para-iniciantes\/","url_meta":{"origin":18133,"position":0},"title":"T\u00e9cnicas Essenciais de MMA para Iniciantes","author":"Dave","date":"Setembro 17, 2026","format":false,"excerpt":"MMA Technique Directory Curated demonstrations for MMA, BJJ, wrestling and Muay Thai. Filter by style, position or category \u2014 tap for coaching notes. 0 of 0 techniques Showing all techniques Clear filters No techniques match these filters. Clear filters Video credits & attribution Videos above are embedded from these instructors'\u2026","rel":"","context":"Similar post","block_context":{"text":"Similar post","link":""},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":4665,"url":"https:\/\/blackbeltwhitehat.com\/pt\/diretorio-de-tecnicas\/impressionante\/combinacoes-de-boxe\/","url_meta":{"origin":18133,"position":1},"title":"Combina\u00e7\u00f5es de boxe","author":"Dave","date":"Maio 18, 2016","format":false,"excerpt":"\u00a0 Aqui est\u00e3o algumas combina\u00e7\u00f5es para experimentar nos pads e no saco de pancadas. Combina\u00e7\u00f5es de Boxe: Jab Duplo, Jab, Cruzado; Jab Duplo, Cruzado; Jab de Esquerda, Cruzado, Gancho de Esquerda, Cruzado; Jab de Esquerda na cabe\u00e7a, Cruzado de Direita no corpo, Gancho de Esquerda na cabe\u00e7a; Jab de Esquerda, Gancho de Esquerda; Jab de Esquerda, Gancho de Esquerda\u2026","rel":"","context":"Similar post","block_context":{"text":"Similar post","link":""},"img":{"alt_text":"boxing jab","src":"https:\/\/i0.wp.com\/blackbeltwhitehat.com\/wp-content\/uploads\/2013\/06\/jab2a.jpg?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":4535,"url":"https:\/\/blackbeltwhitehat.com\/pt\/diretorio-de-tecnicas\/impressionante\/cruz-e-balcao-de-cruz\/","url_meta":{"origin":18133,"position":2},"title":"Como lan\u00e7ar um cruzado no boxe","author":"Dave","date":"Maio 13, 2016","format":false,"excerpt":"O cruzado \u00e9 desferido com o dorso da m\u00e3o, ao contr\u00e1rio do jab, que \u00e9 desferido com a m\u00e3o mais pr\u00f3xima do oponente. Tamb\u00e9m \u00e9 conhecido como &quot;dorso da m\u00e3o&quot;, &quot;direito direto&quot; ou &quot;esquerdo direto&quot;. Convencionalmente, um cruzado \u00e9 desferido com uma &quot;rota\u00e7\u00e3o&quot; no final, em que...","rel":"","context":"Similar post","block_context":{"text":"Similar post","link":""},"img":{"alt_text":"cross boxing punch","src":"https:\/\/i0.wp.com\/blackbeltwhitehat.com\/wp-content\/uploads\/2016\/05\/cross_bw.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blackbeltwhitehat.com\/wp-content\/uploads\/2016\/05\/cross_bw.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blackbeltwhitehat.com\/wp-content\/uploads\/2016\/05\/cross_bw.png?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":4567,"url":"https:\/\/blackbeltwhitehat.com\/pt\/diretorio-de-tecnicas\/luta-livre\/gancho-de-sobregancho\/","url_meta":{"origin":18133,"position":3},"title":"Overhook no MMA e no Wrestling","author":"Dave","date":"Maio 15, 2016","format":false,"excerpt":"O overhook no wrestling, tamb\u00e9m chamado de &quot;wizzer&quot;, \u00e9 um golpe que consiste em passar o bra\u00e7o por cima e ao redor do bra\u00e7o do oponente. \u00c9 frequentemente usado como contra-ataque a um &quot;underhook&quot; - quando o bra\u00e7o do oponente passa por baixo da sua axila. Na imagem abaixo, Anderson Silva est\u00e1 com um...","rel":"","context":"Similar post","block_context":{"text":"Similar post","link":""},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blackbeltwhitehat.com\/wp-content\/uploads\/2019\/05\/overhook3.gif?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":70,"url":"https:\/\/blackbeltwhitehat.com\/pt\/","url_meta":{"origin":18133,"position":4},"title":"Lar","author":"Dave","date":"Dezembro 14, 2012","format":false,"excerpt":"Bem-vindo(a) ao meu blog de fitness e MMA. \u00c9 basicamente uma mistura de tudo o que me interessa. Sou ex-lutador de MMA e kickboxer. Sou formado com louvor em Ci\u00eancias do Esporte pela Universidade de Loughborough e tenho mestrado em Exerc\u00edcio e Nutri\u00e7\u00e3o. Tamb\u00e9m administro meu pr\u00f3prio\u2026","rel":"","context":"Similar post","block_context":{"text":"Similar post","link":""},"img":{"alt_text":"mma blog","src":"https:\/\/i0.wp.com\/blackbeltwhitehat.com\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_l6p36ml6p36ml6p3.png?fit=1200%2C545&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blackbeltwhitehat.com\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_l6p36ml6p36ml6p3.png?fit=1200%2C545&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/blackbeltwhitehat.com\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_l6p36ml6p36ml6p3.png?fit=1200%2C545&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/blackbeltwhitehat.com\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_l6p36ml6p36ml6p3.png?fit=1200%2C545&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/blackbeltwhitehat.com\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_l6p36ml6p36ml6p3.png?fit=1200%2C545&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":4537,"url":"https:\/\/blackbeltwhitehat.com\/pt\/diretorio-de-tecnicas\/impressionante\/","url_meta":{"origin":18133,"position":5},"title":"Impressionante","author":"Dave","date":"Maio 13, 2016","format":false,"excerpt":"T\u00e9cnicas de Golpes e Boxe Um guia pr\u00e1tico de t\u00e9cnicas de golpes e boxe para manter seu jogo de MMA e boxe em dia. Seja voc\u00ea iniciante ou lutador avan\u00e7ado, ter as t\u00e9cnicas organizadas desta forma \u00e9 sempre \u00fatil. Como dar um jab no boxe e no MMA Como dar um double-draw\u2026","rel":"","context":"Similar post","block_context":{"text":"Similar post","link":""},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/blackbeltwhitehat.com\/pt\/wp-json\/wp\/v2\/pages\/18133","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blackbeltwhitehat.com\/pt\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/blackbeltwhitehat.com\/pt\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/blackbeltwhitehat.com\/pt\/wp-json\/wp\/v2\/users\/41980142"}],"replies":[{"embeddable":true,"href":"https:\/\/blackbeltwhitehat.com\/pt\/wp-json\/wp\/v2\/comments?post=18133"}],"version-history":[{"count":4,"href":"https:\/\/blackbeltwhitehat.com\/pt\/wp-json\/wp\/v2\/pages\/18133\/revisions"}],"predecessor-version":[{"id":18143,"href":"https:\/\/blackbeltwhitehat.com\/pt\/wp-json\/wp\/v2\/pages\/18133\/revisions\/18143"}],"wp:attachment":[{"href":"https:\/\/blackbeltwhitehat.com\/pt\/wp-json\/wp\/v2\/media?parent=18133"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}