SuperSkoleGames er nu åben






Dobbelt bogstavhjul

:root { --bg1: #f7fbff; --bg2: #eef5ff; --ink: #18324a; --muted: #5f7488; --card: rgba(255,255,255,.94); --accent: #2457ff; --accent2: #00a870; --line: #d8e4ef; --shadow: 0 18px 50px rgba(41, 76, 110, .15); }

* { box-sizing: border-box; }

body { margin: 0; min-height: 100vh; font-family: Inter, ui-rounded, "Segoe UI", Arial, sans-serif; color: var(--ink); background: radial-gradient(circle at top left, rgba(36,87,255,.12), transparent 35%), radial-gradient(circle at bottom right, rgba(0,168,112,.13), transparent 35%), linear-gradient(145deg, var(--bg1), var(--bg2)); }

.wrap { width: min(1200px, 96vw); margin: 0 auto; padding: 28px 0 44px; }

header { text-align: center; margin-bottom: 22px; }

h1 { margin: 0; font-size: clamp(2rem, 4vw, 3.4rem); letter-spacing: -.04em; }

.subtitle { margin: 10px auto 0; max-width: 760px; color: var(--muted); font-size: 1.05rem; line-height: 1.5; }

.toolbar { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; margin: 20px 0 26px; }

button { border: 0; border-radius: 14px; padding: 12px 18px; font-size: 1rem; font-weight: 750; cursor: pointer; transition: transform .15s ease, box-shadow .15s ease, opacity .15s ease; }

button:hover { transform: translateY(-1px); } button:active { transform: translateY(1px); }

.secondary { background: #fff; color: var(--ink); box-shadow: 0 8px 22px rgba(41,76,110,.10); border: 1px solid var(--line); }

.all-spin { color: white; background: linear-gradient(135deg, var(--accent), #6d4cff); box-shadow: 0 12px 28px rgba(36,87,255,.25); }

.wheels { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); gap: 18px; align-items: center; }

.wheel-card { background: var(--card); border: 1px solid rgba(216,228,239,.95); border-radius: 26px; padding: 22px; box-shadow: var(--shadow); backdrop-filter: blur(8px); }

.wheel-title { margin: 0 0 16px; text-align: center; font-size: 1.35rem; }

.wheel-stage { display: grid; place-items: center; min-height: 390px; position: relative; }

.pointer { position: absolute; top: 7px; z-index: 4; width: 0; height: 0; border-left: 18px solid transparent; border-right: 18px solid transparent; border-top: 34px solid #ff6846; filter: drop-shadow(0 4px 3px rgba(0,0,0,.18)); }

canvas { width: min(360px, 80vw); height: min(360px, 80vw); max-width: 100%; display: block; filter: drop-shadow(0 14px 18px rgba(24,50,74,.17)); }

.controls { display: grid; gap: 12px; margin-top: 10px; }

.spin-btn { color: white; background: linear-gradient(135deg, var(--accent), #4d7dff); box-shadow: 0 10px 24px rgba(36,87,255,.22); }

.wheel-card.right .spin-btn { background: linear-gradient(135deg, var(--accent2), #22bf84); box-shadow: 0 10px 24px rgba(0,168,112,.20); }

.center-result { display: grid; gap: 12px; justify-items: center; align-content: center; padding: 18px 4px; }

.center-label { margin: 0; color: var(--muted); font-weight: 800; text-align: center; }

.result-pair { display: flex; gap: 6px; align-items: center; justify-content: center; }

.result { width: 92px; height: 92px; background: #ffffff; border: 3px solid var(--line); border-radius: 18px; display: grid; place-items: center; text-align: center; font-size: 2.35rem; font-weight: 900; letter-spacing: .03em; box-shadow: 0 12px 28px rgba(41,76,110,.13); }

#result1 { border-color: rgba(36,87,255,.55); } #result2 { border-color: rgba(0,168,112,.55); }

details { margin-top: 16px; border-top: 1px solid var(--line); padding-top: 14px; }

summary { cursor: pointer; font-weight: 800; color: var(--ink); }

.inputs { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; margin-top: 12px; }

.inputs input { width: 100%; border: 1px solid var(--line); border-radius: 11px; padding: 10px 6px; text-align: center; text-transform: uppercase; font-size: 1.05rem; font-weight: 800; color: var(--ink); background: white; outline: none; }

.inputs input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(36,87,255,.12); }

.tip { margin: 20px auto 0; padding: 14px 18px; max-width: 820px; text-align: center; color: var(--muted); background: rgba(255,255,255,.75); border-radius: 16px; border: 1px solid rgba(216,228,239,.9); line-height: 1.45; }

@media (max-width: 900px) { .wheels { grid-template-columns: 1fr; } .center-result { order: 2; padding: 4px 0; } .wheel-card.left { order: 1; } .wheel-card.right { order: 3; } .wheel-stage { min-height: 340px; } .inputs { grid-template-columns: repeat(4, minmax(0, 1fr)); } }



Dobbelt bogstavhjul

Skriv op til to bogstaver i hvert felt. Drej hjulene hver for sig eller samtidig.


Hjul 1

Redigér felter

Læs sammen

Hjul 2

Redigér felter

Tip: Brug fx BR, KL, ST på det ene hjul og A, I, O, Å på det andet.
Så kan eleverne kombinere begyndelser og endelser.

const colors1 = ["#2457ff","#5f7dff","#8d66ff","#c65de8","#ff6f91","#ff8d5d","#ffc14d","#55c990"]; const colors2 = ["#00a870","#19ba8a","#55c990","#9acb52","#e3c643","#ffb04d","#ff7d63","#3f8ce8"];

class Wheel { constructor(canvasId, inputContainerId, resultId, buttonId, colors, defaults) { this.canvas = document.getElementById(canvasId); this.ctx = this.canvas.getContext("2d"); this.inputContainer = document.getElementById(inputContainerId); this.resultEl = document.getElementById(resultId); this.button = document.getElementById(buttonId); this.colors = colors; this.values = [...defaults]; this.rotation = 0; this.isSpinning = false; this.buildInputs(); this.draw(); this.button.addEventListener("click", () => this.spin()); }

buildInputs() { this.inputContainer.innerHTML = ""; this.values.forEach((value, index) => { const input = document.createElement("input"); input.value = value; input.maxLength = 2; input.setAttribute("aria-label", `Felt ${index + 1}`); input.addEventListener("input", () => { input.value = input.value.toUpperCase().slice(0, 2); this.values[index] = input.value || " "; this.draw(); }); this.inputContainer.appendChild(input); }); }

draw() { const ctx = this.ctx; const w = this.canvas.width; const h = this.canvas.height; const cx = w / 2; const cy = h / 2; const radius = Math.min(w, h) * 0.43; const slice = (Math.PI * 2) / this.values.length;

ctx.clearRect(0, 0, w, h); ctx.save(); ctx.translate(cx, cy); ctx.rotate(this.rotation);

this.values.forEach((value, i) => { const start = -Math.PI / 2 + i * slice; const end = start + slice;

ctx.beginPath(); ctx.moveTo(0, 0); ctx.arc(0, 0, radius, start, end); ctx.closePath(); ctx.fillStyle = this.colors[i % this.colors.length]; ctx.fill(); ctx.lineWidth = 8; ctx.strokeStyle = "#ffffff"; ctx.stroke();

const angle = start + slice / 2; ctx.save(); ctx.rotate(angle); ctx.translate(radius * 0.66, 0); ctx.rotate(Math.PI / 2); ctx.fillStyle = "#ffffff"; ctx.font = "900 58px Segoe UI, Arial, sans-serif"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.shadowColor = "rgba(0,0,0,.18)"; ctx.shadowBlur = 4; ctx.fillText(value || " ", 0, 0); ctx.restore(); });

ctx.beginPath(); ctx.arc(0, 0, radius * 0.17, 0, Math.PI * 2); ctx.fillStyle = "#ffffff"; ctx.fill(); ctx.lineWidth = 8; ctx.strokeStyle = "#d9e4ee"; ctx.stroke();

ctx.beginPath(); ctx.arc(0, 0, radius * 0.07, 0, Math.PI * 2); ctx.fillStyle = "#18324a"; ctx.fill();

ctx.restore(); }

selectedIndex() { const full = Math.PI * 2; const slice = full / this.values.length; const normalized = ((-this.rotation) % full + full) % full; return Math.floor(normalized / slice) % this.values.length; }

spin() { if (this.isSpinning) return Promise.resolve(); this.isSpinning = true; this.button.disabled = true; this.resultEl.textContent = "…";

const start = this.rotation; const full = Math.PI * 2; const slice = full / this.values.length; const targetIndex = Math.floor(Math.random() * this.values.length); const extraTurns = 5 + Math.floor(Math.random() * 3); const desiredRotation = -(targetIndex + 0.5) * slice; let forwardDistance = ((desiredRotation - start) % full + full) % full; const target = start + extraTurns * full + forwardDistance; const duration = 2600; const startTime = performance.now();

return new Promise(resolve => { const animate = now => { const t = Math.min(1, (now - startTime) / duration); const eased = 1 - Math.pow(1 - t, 4); this.rotation = start + (target - start) * eased; this.draw();

if (t { await Promise.all([wheel1.spin(), wheel2.spin()]); });

document.getElementById("resetAll").addEventListener("click", () => { wheel1.reset(defaults1); wheel2.reset(defaults2); });