Skip to content

Instantly share code, notes, and snippets.

@MathewDominic
Created February 6, 2026 06:29
Show Gist options
  • Select an option

  • Save MathewDominic/66c4f4ce10cfaed943178c8fe664584f to your computer and use it in GitHub Desktop.

Select an option

Save MathewDominic/66c4f4ce10cfaed943178c8fe664584f to your computer and use it in GitHub Desktop.
A companion tracker for playing Scoundrel (single player card game). It helps you win by tracking which cards are still in the dungeon.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Scoundrel Tracker</title>
<style>
body {
font-family: Arial, sans-serif;
background: #1e1e2f;
color: white;
text-align: center;
margin: 0;
}
h1 { margin-top: 20px; }
h2 { margin-top: 30px; }
.section { margin: 30px 0; }
.cards {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 8px;
margin-top: 10px;
}
.row {
display: flex;
justify-content: center;
gap: 8px;
margin-top: 8px;
}
.card {
width: 50px;
height: 70px;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
cursor: pointer;
user-select: none;
transition: 0.2s;
}
.weapon { background: #555; }
.potion { background: #a33; }
.monster { background: #333; }
.used {
opacity: 0.3;
text-decoration: line-through;
}
.counter {
margin-top: 8px;
font-size: 14px;
}
#totalCards {
margin-top: 10px;
font-size: 18px;
font-weight: bold;
}
button {
padding: 6px 12px;
margin-top: 20px;
cursor: pointer;
}
/* Help Button */
#helpBtn {
position: absolute;
top: 15px;
right: 15px;
width: 35px;
height: 35px;
border-radius: 50%;
background: #444;
color: white;
font-weight: bold;
border: none;
cursor: pointer;
}
/* Modal */
.modal {
display: none;
position: fixed;
inset: 0;
background: rgba(0,0,0,0.6);
justify-content: center;
align-items: center;
}
.modal-content {
background: #2b2b3d;
padding: 20px;
width: 300px;
border-radius: 8px;
text-align: left;
}
.close-btn {
margin-top: 15px;
width: 100%;
}
</style>
</head>
<body>
<button id="helpBtn">?</button>
<h1>Scoundrel Tracker</h1>
<div id="totalCards"></div>
<div id="app"></div>
<button onclick="resetAll()">Reset All</button>
<!-- Modal -->
<!-- Modal -->
<div class="modal" id="helpModal">
<div class="modal-content">
<p>
This is a companion tracker for playing <b>Scoundrel</b>.
It helps you track what cards are still in the dungeon.
<br><br>
<b>How to use while playing:</b><br><br>
• At the start of the game, all cards are available.<br><br>
• Whenever a monster, weapon, or potion is permanently discarded,
tap that card here to mark it as used.<br><br>
• Use the Remaining Strength to understand how dangerous
the dungeon still is.<br><br>
• Use Total Cards Remaining to estimate deck size
and future draw probability.
<br><br>
New to Scoundrel?
<br>
<a href="https://www.youtube.com/watch?v=Gt2tYzM93h4" target="_blank" style="color:#66b3ff;">
Watch how to play
</a>
</p>
<button class="close-btn" onclick="closeHelp()">Close</button>
</div>
</div>
<script>
const app = document.getElementById("app");
const totalCardsEl = document.getElementById("totalCards");
const helpBtn = document.getElementById("helpBtn");
const helpModal = document.getElementById("helpModal");
helpBtn.onclick = () => helpModal.style.display = "flex";
helpModal.onclick = (e) => {
if (e.target === helpModal) closeHelp();
};
function closeHelp() {
helpModal.style.display = "none";
}
const sections = [
{
title: "Weapons (2–10)",
type: "weapon",
values: [2,3,4,5,6,7,8,9,10]
},
{
title: "Potions (2–10)",
type: "potion",
values: [2,3,4,5,6,7,8,9,10]
},
{
title: "Monsters (2–14 ×2)",
type: "monster",
values: [
[2,3,4,5,6,7,8,9,10,11,12,13,14],
[2,3,4,5,6,7,8,9,10,11,12,13,14]
]
}
];
function render() {
app.innerHTML = "";
sections.forEach((section, index) => {
const wrapper = document.createElement("div");
wrapper.className = "section";
const title = document.createElement("h2");
title.innerText = section.title;
wrapper.appendChild(title);
if (Array.isArray(section.values[0])) {
section.values.forEach(rowValues => {
const rowDiv = document.createElement("div");
rowDiv.className = "row";
rowValues.forEach(val => {
rowDiv.appendChild(createCard(val, section.type));
});
wrapper.appendChild(rowDiv);
});
} else {
const cardsDiv = document.createElement("div");
cardsDiv.className = "cards";
section.values.forEach(val => {
cardsDiv.appendChild(createCard(val, section.type));
});
wrapper.appendChild(cardsDiv);
}
const counter = document.createElement("div");
counter.className = "counter";
counter.id = "counter-" + index;
wrapper.appendChild(counter);
app.appendChild(wrapper);
});
updateStats();
}
function createCard(val, type) {
const card = document.createElement("div");
card.className = `card ${type}`;
card.innerText = val;
card.dataset.value = val;
card.onclick = () => {
card.classList.toggle("used");
updateStats();
};
return card;
}
function updateStats() {
let totalCardsLeft = 0;
document.querySelectorAll(".section").forEach((sectionEl, index) => {
let sectionStrength = 0;
let sectionCardsLeft = 0;
sectionEl.querySelectorAll(".card").forEach(card => {
if (!card.classList.contains("used")) {
sectionStrength += parseInt(card.dataset.value);
sectionCardsLeft++;
}
});
totalCardsLeft += sectionCardsLeft;
document.getElementById("counter-" + index).innerText =
`Remaining Strength: ${sectionStrength} | Cards Left: ${sectionCardsLeft}`;
});
totalCardsEl.innerText =
`Total Cards Remaining: ${totalCardsLeft} / 44`;
}
function resetAll() {
document.querySelectorAll(".card").forEach(card => {
card.classList.remove("used");
});
updateStats();
}
render();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment