Free shipping on orders over $40!

Shopping Cart

  • No products in the cart.
Menu

1-16 Table top Wound Tracker (Choose a Colour)

Original price was: $13.00.Current price is: $9.00.
  • SKU:ZFOQ6831027461
  • Category:

Share:
  • 30 days easy returns
  • Free shipping on orders over $40
  • Guaranteed safe & secure checkout
Quantity Total Each () New Discounted Total () Saving ()
1 2.99 2.99
3+ 2.84 8.52 0.45 / 5% Off
5+ 2.69 13.46 1.49 / 10% Off
10+ 2.54 25.42 4.49 / 15% Off
15+ 2.39 35.88 8.97 / 20% Off

Multi-Buy Calculator

Enter Quantity:

Total Each: 2.99

New Discounted Total: 2.99

Savings:

The Only Clickable Wound Tracker for Warhammer 40K

Tired of losing track of wounds mid-game?

This is the ONLY clickable wound tracker on the market designed to lock each wound in place so nothing shifts when you pick it up or adjust your models.

Why You’ll Love It:

  • Secure click-to-lock mechanism no more knocked dials or lost wounds
  • Clear, bold numbers easy to read at a glance
  • Smooth & satisfying clicks precise control over tracking
  • Durable and battle-ready built to last through heavy use
  • Minimalist design complements your painted armies perfectly
  • Compatible with Warhammer 40K, Kill Team, AoS & more

Whether you’re fighting for glory at a tournament or battling friends at home, this wound tracker gives you the accuracy and confidence every commander needs.

No more guesswork. No more accidental resets. Just reliable, click-by-click tracking.

(() => { // — Config — const DISCOUNTS = [ { min: 15, rate: 0.20, label: “20% Off” }, { min: 10, rate: 0.15, label: “15% Off” }, { min: 5, rate: 0.10, label: “10% Off” }, { min: 3, rate: 0.05, label: “5% Off” }, { min: 1, rate: 0.00, label: “” }, ]; const currencyFormatter = new Intl.NumberFormat(‘en-GB’, { style: ‘currency’, currency: ‘GBP’, minimumFractionDigits: 2 }); let currentVariantPrice = null; // in GBP (e.g., 12.99) // — Price helpers — function getDiscountForQty(qty) { for (const tier of DISCOUNTS) { if (qty >= tier.min) return tier; } return { rate: 0, label: “” }; } function readPriceFromDOM() { // Try a few common selectors used by Shopify themes const candidates = [ ‘[data-product-price]’, ‘.price .price-item–regular’, ‘.product__price .price-item–regular’, ‘.price__regular .price-item’, ‘[itemprop=”price”]’, ‘[data-price]’ ]; for (const sel of candidates) { const el = document.querySelector(sel); if (el && el.textContent) { const raw = el.textContent.replace(/[^\d.,]/g, ”).replace(‘,’, ‘.’); const val = parseFloat(raw); if (!Number.isNaN(val)) return val; } } return null; } function readVariantFromJSON() { // Works on most OS 2.0 themes const jsonEl = document.querySelector(‘script[type=”application/json”][data-product], script[id*=”ProductJson”]’); if (!jsonEl) return null; try { const product = JSON.parse(jsonEl.textContent); const qsId = new URLSearchParams(location.search).get(‘variant’); if (qsId && product.variants) { const v = product.variants.find(v => String(v.id) === String(qsId)); if (v) return v; } // fallback: first available or first variant return (product.variants || []).find(v => v.available) || (product.variants || [])[0] || null; } catch { return null; } } function getBasePriceGBP() { // 1) From live variant change listener if (typeof currentVariantPrice === ‘number’) return currentVariantPrice; // 2) From DOM price const domVal = readPriceFromDOM(); if (typeof domVal === ‘number’) return domVal; // 3) From product JSON const v = readVariantFromJSON(); if (v && typeof v.price === ‘number’) return v.price / 100; // JSON is in cents // 4) Fallback to your default return 2.99; } // — Calculator binding — function bindCalculator() { const qtyInput = document.getElementById(‘quantity’); const pricePerItemEl = document.getElementById(‘pricePerItem’); const totalPriceEl = document.getElementById(‘totalPrice’); const savingsEl = document.getElementById(‘savings’); if (!qtyInput || !pricePerItemEl || !totalPriceEl || !savingsEl) return; // Avoid double-binding after re-renders if (qtyInput.dataset.bound === ‘1’) return; qtyInput.dataset.bound = ‘1’; const recalc = () => { const qty = Math.max(1, parseInt(qtyInput.value, 10) || 1); const { rate, label } = getDiscountForQty(qty); const base = getBasePriceGBP(); const totalFull = base * qty; const discountAmount = totalFull * rate; const totalDiscounted = totalFull – discountAmount; const perItem = totalDiscounted / qty; pricePerItemEl.textContent = currencyFormatter.format(perItem); totalPriceEl.textContent = currencyFormatter.format(totalDiscounted); savingsEl.textContent = rate > 0 ? `${currencyFormatter.format(discountAmount)} / ${label}` : ”; }; qtyInput.addEventListener(‘input’, recalc); recalc(); // initial } // — React to variant changes (modern Shopify themes dispatch this) — document.addEventListener(‘variant:change’, (e) => { if (e && e.detail && e.detail.variant && typeof e.detail.variant.price === ‘number’) { currentVariantPrice = e.detail.variant.price / 100; // convert cents->GBP bindCalculator(); // Recalculate immediately if qty exists const qtyInput = document.getElementById(‘quantity’); if (qtyInput) qtyInput.dispatchEvent(new Event(‘input’, { bubbles: true })); } }); // — Re-bind after any DOM updates/section re-renders — const mo = new MutationObserver(() => { bindCalculator(); }); mo.observe(document.body, { childList: true, subtree: true }); // — Initial bind on page load — if (document.readyState === ‘loading’) { document.addEventListener(‘DOMContentLoaded’, bindCalculator, { once: true }); } else { bindCalculator(); } // — Also handle URL param changes (?variant=…) without full reload — window.addEventListener(‘popstate’, bindCalculator);})();

Add a Review

Your email address will not be published. Required fields are marked *

Related Products

Subscribe our Newsletter