edu-boardgame-generator/minigames/spotdiff.js

392 lines
19 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* minigames/spotdiff.js
* 🔍 Fehler finden — Finde alle Unterschiede zwischen den zwei Bildern!
*/
window.MG_spotdiff = (function() {
const ID = 'spotdiff';
const EMOJI = '🔍';
const NAME = 'Fehler finden';
const DESC = 'Finde alle Unterschiede zwischen den zwei Bildern!';
const CONTROLS = 'Mausklick';
const MULTI = 1;
// ── Bild-Sets (canvas-gezeichnete Szenen) ────────────────────────────────
// Jede Szene besteht aus drawA(ctx,W,H) und drawB(ctx,W,H),
// plus einer Liste von Unterschied-Hotspots { x, y, r } (relativ, 01)
const SCENES = [
{
name: 'Bauernhof',
drawA(ctx, W, H) {
// Himmel
ctx.fillStyle = '#7dd3fc'; ctx.fillRect(0, 0, W, H * 0.55);
// Gras
ctx.fillStyle = '#4ade80'; ctx.fillRect(0, H * 0.55, W, H * 0.45);
// Sonne
ctx.fillStyle = '#fbbf24'; ctx.beginPath(); ctx.arc(W*0.15, H*0.18, H*0.1, 0, Math.PI*2); ctx.fill();
// Haus
ctx.fillStyle = '#f87171'; ctx.fillRect(W*0.3, H*0.3, W*0.25, H*0.28);
ctx.fillStyle = '#7f1d1d'; ctx.beginPath(); ctx.moveTo(W*0.27,H*0.3); ctx.lineTo(W*0.425,H*0.12); ctx.lineTo(W*0.58,H*0.3); ctx.fill();
// Fenster (2)
ctx.fillStyle = '#bae6fd'; ctx.fillRect(W*0.34, H*0.38, W*0.06, H*0.07);
ctx.fillStyle = '#bae6fd'; ctx.fillRect(W*0.45, H*0.38, W*0.06, H*0.07);
// Tür
ctx.fillStyle = '#78350f'; ctx.fillRect(W*0.39, H*0.46, W*0.05, H*0.12);
// Baum (3 Kreise)
ctx.fillStyle = '#16a34a'; ctx.beginPath(); ctx.arc(W*0.75, H*0.38, W*0.06, 0, Math.PI*2); ctx.fill();
ctx.fillStyle = '#15803d'; ctx.beginPath(); ctx.arc(W*0.72, H*0.46, W*0.05, 0, Math.PI*2); ctx.fill();
ctx.fillStyle = '#14532d'; ctx.beginPath(); ctx.arc(W*0.79, H*0.44, W*0.05, 0, Math.PI*2); ctx.fill();
ctx.fillStyle = '#78350f'; ctx.fillRect(W*0.74, H*0.5, W*0.02, H*0.08);
// Wolke
ctx.fillStyle = '#fff';
ctx.beginPath(); ctx.arc(W*0.55, H*0.14, W*0.05, 0, Math.PI*2); ctx.fill();
ctx.beginPath(); ctx.arc(W*0.62, H*0.11, W*0.06, 0, Math.PI*2); ctx.fill();
ctx.beginPath(); ctx.arc(W*0.69, H*0.14, W*0.05, 0, Math.PI*2); ctx.fill();
// Vogel (klein, V-Form im Himmel)
ctx.strokeStyle = '#1f2937'; ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(W*0.85, H*0.23); ctx.lineTo(W*0.88, H*0.20); ctx.lineTo(W*0.91, H*0.23);
ctx.stroke();
},
drawB(ctx, W, H) {
// Himmel — IDENTISCH zu A
ctx.fillStyle = '#7dd3fc'; ctx.fillRect(0, 0, W, H * 0.55);
// Gras
ctx.fillStyle = '#4ade80'; ctx.fillRect(0, H * 0.55, W, H * 0.45);
// Sonne (UNTERSCHIED 1: weiter oben)
ctx.fillStyle = '#fbbf24'; ctx.beginPath(); ctx.arc(W*0.15, H*0.10, H*0.1, 0, Math.PI*2); ctx.fill();
// Haus
ctx.fillStyle = '#f87171'; ctx.fillRect(W*0.3, H*0.3, W*0.25, H*0.28);
ctx.fillStyle = '#7f1d1d'; ctx.beginPath(); ctx.moveTo(W*0.27,H*0.3); ctx.lineTo(W*0.425,H*0.12); ctx.lineTo(W*0.58,H*0.3); ctx.fill();
// Fenster (UNTERSCHIED 2: zweites Fenster ist ROT statt blau)
ctx.fillStyle = '#bae6fd'; ctx.fillRect(W*0.34, H*0.38, W*0.06, H*0.07);
ctx.fillStyle = '#f87171'; ctx.fillRect(W*0.45, H*0.38, W*0.06, H*0.07);
// Tür (UNTERSCHIED 3: fehlt — Wand bleibt durchgehend rot)
// Baum (UNTERSCHIED 4: kleiner)
ctx.fillStyle = '#16a34a'; ctx.beginPath(); ctx.arc(W*0.75, H*0.42, W*0.04, 0, Math.PI*2); ctx.fill();
ctx.fillStyle = '#15803d'; ctx.beginPath(); ctx.arc(W*0.72, H*0.48, W*0.035, 0, Math.PI*2); ctx.fill();
ctx.fillStyle = '#14532d'; ctx.beginPath(); ctx.arc(W*0.79, H*0.46, W*0.035, 0, Math.PI*2); ctx.fill();
ctx.fillStyle = '#78350f'; ctx.fillRect(W*0.74, H*0.5, W*0.02, H*0.08);
// Wolke (UNTERSCHIED 5: fehlt)
// Vogel — bleibt
ctx.strokeStyle = '#1f2937'; ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(W*0.85, H*0.23); ctx.lineTo(W*0.88, H*0.20); ctx.lineTo(W*0.91, H*0.23);
ctx.stroke();
},
spots: [
{ x: 0.15, y: 0.10, r: 0.10, label: 'Sonne (weiter oben)' },
{ x: 0.48, y: 0.41, r: 0.06, label: 'Rotes Fenster' },
{ x: 0.42, y: 0.52, r: 0.05, label: 'Fehlende Tür' },
{ x: 0.75, y: 0.44, r: 0.08, label: 'Kleinerer Baum' },
{ x: 0.62, y: 0.13, r: 0.10, label: 'Fehlende Wolke' },
],
},
// ── Szene 2: STRAND ──────────────────────────────────────────────────
{
name: 'Strand',
drawA(ctx, W, H) {
// Himmel
ctx.fillStyle = '#7dd3fc'; ctx.fillRect(0, 0, W, H * 0.6);
// Meer
ctx.fillStyle = '#0e7490'; ctx.fillRect(0, H * 0.55, W, H * 0.12);
// Sand
ctx.fillStyle = '#fde68a'; ctx.fillRect(0, H * 0.67, W, H * 0.33);
// Sonne (oben rechts)
ctx.fillStyle = '#fbbf24'; ctx.beginPath(); ctx.arc(W*0.8, H*0.18, H*0.08, 0, Math.PI*2); ctx.fill();
// Palme (links)
ctx.fillStyle = '#78350f'; ctx.fillRect(W*0.13, H*0.4, W*0.022, H*0.4);
ctx.fillStyle = '#15803d';
for (let i = 0; i < 5; i++) {
ctx.save();
ctx.translate(W*0.14, H*0.4);
ctx.rotate((i - 2) * 0.35);
ctx.beginPath(); ctx.ellipse(0, -H*0.04, W*0.09, H*0.025, 0, 0, Math.PI*2); ctx.fill();
ctx.restore();
}
// Kokosnüsse (2)
ctx.fillStyle = '#451a03';
ctx.beginPath(); ctx.arc(W*0.155, H*0.41, W*0.012, 0, Math.PI*2); ctx.fill();
ctx.beginPath(); ctx.arc(W*0.13, H*0.43, W*0.012, 0, Math.PI*2); ctx.fill();
// Sandburg (Mitte unten)
ctx.fillStyle = '#d97706';
ctx.fillRect(W*0.42, H*0.74, W*0.18, H*0.14);
// Türme links + rechts + Mitte
ctx.fillRect(W*0.41, H*0.7, W*0.04, H*0.04);
ctx.fillRect(W*0.49, H*0.66, W*0.04, H*0.08);
ctx.fillRect(W*0.57, H*0.7, W*0.04, H*0.04);
// Flagge am mittleren Turm
ctx.fillStyle = '#dc2626';
ctx.beginPath(); ctx.moveTo(W*0.51, H*0.62); ctx.lineTo(W*0.55, H*0.64); ctx.lineTo(W*0.51, H*0.66); ctx.fill();
ctx.strokeStyle = '#1f2937'; ctx.lineWidth = 1;
ctx.beginPath(); ctx.moveTo(W*0.51, H*0.62); ctx.lineTo(W*0.51, H*0.7); ctx.stroke();
// Schiff am Horizont (rechts)
ctx.fillStyle = '#1f2937'; ctx.fillRect(W*0.78, H*0.58, W*0.08, H*0.025);
ctx.fillStyle = '#fff'; ctx.beginPath();
ctx.moveTo(W*0.82, H*0.58); ctx.lineTo(W*0.82, H*0.5); ctx.lineTo(W*0.85, H*0.58); ctx.fill();
// Möwe (V)
ctx.strokeStyle = '#1f2937'; ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(W*0.36, H*0.22); ctx.lineTo(W*0.4, H*0.24); ctx.lineTo(W*0.44, H*0.22);
ctx.stroke();
},
drawB(ctx, W, H) {
// Himmel — IDENTISCH zu A
ctx.fillStyle = '#7dd3fc'; ctx.fillRect(0, 0, W, H * 0.6);
// Meer
ctx.fillStyle = '#0e7490'; ctx.fillRect(0, H * 0.55, W, H * 0.12);
// Sand
ctx.fillStyle = '#fde68a'; ctx.fillRect(0, H * 0.67, W, H * 0.33);
// Sonne (UNTERSCHIED 1: weiter mittig)
ctx.fillStyle = '#fbbf24'; ctx.beginPath(); ctx.arc(W*0.5, H*0.18, H*0.08, 0, Math.PI*2); ctx.fill();
// Palme (links)
ctx.fillStyle = '#78350f'; ctx.fillRect(W*0.13, H*0.4, W*0.022, H*0.4);
ctx.fillStyle = '#15803d';
for (let i = 0; i < 5; i++) {
ctx.save();
ctx.translate(W*0.14, H*0.4);
ctx.rotate((i - 2) * 0.35);
ctx.beginPath(); ctx.ellipse(0, -H*0.04, W*0.09, H*0.025, 0, 0, Math.PI*2); ctx.fill();
ctx.restore();
}
// Kokosnüsse (UNTERSCHIED 2: nur EINE statt zwei)
ctx.fillStyle = '#451a03';
ctx.beginPath(); ctx.arc(W*0.155, H*0.41, W*0.012, 0, Math.PI*2); ctx.fill();
// Sandburg
ctx.fillStyle = '#d97706';
ctx.fillRect(W*0.42, H*0.74, W*0.18, H*0.14);
ctx.fillRect(W*0.41, H*0.7, W*0.04, H*0.04);
ctx.fillRect(W*0.49, H*0.66, W*0.04, H*0.08);
ctx.fillRect(W*0.57, H*0.7, W*0.04, H*0.04);
// Flagge fehlt (UNTERSCHIED 3)
ctx.strokeStyle = '#1f2937'; ctx.lineWidth = 1;
ctx.beginPath(); ctx.moveTo(W*0.51, H*0.62); ctx.lineTo(W*0.51, H*0.7); ctx.stroke();
// Schiff fehlt (UNTERSCHIED 4)
// Möwe fehlt (UNTERSCHIED 5)
},
spots: [
{ x: 0.50, y: 0.18, r: 0.10, label: 'Sonne (weiter mittig)' },
{ x: 0.155, y: 0.43, r: 0.04, label: 'Fehlende Kokosnuss' },
{ x: 0.52, y: 0.64, r: 0.05, label: 'Fehlende Flagge' },
{ x: 0.82, y: 0.55, r: 0.08, label: 'Fehlendes Schiff' },
{ x: 0.40, y: 0.23, r: 0.07, label: 'Fehlende Möwe' },
],
},
// ── Szene 3: WELTRAUM ─────────────────────────────────────────────────
{
name: 'Weltraum',
drawA(ctx, W, H) {
// Hintergrund: tiefes Nachtblau
ctx.fillStyle = '#0c0a2e'; ctx.fillRect(0, 0, W, H);
// Sterne (10 Stück)
ctx.fillStyle = '#fff';
const stars = [[0.10,0.15],[0.22,0.32],[0.35,0.10],[0.48,0.25],[0.60,0.12],
[0.72,0.30],[0.85,0.18],[0.18,0.55],[0.90,0.50],[0.05,0.75]];
stars.forEach(([sx,sy])=>{ ctx.beginPath(); ctx.arc(sx*W, sy*H, 2, 0, Math.PI*2); ctx.fill(); });
// Großer Planet rechts mit Ringen (Saturn-Style)
const px = W*0.78, py = H*0.45, pr = H*0.13;
ctx.fillStyle = '#fb923c'; ctx.beginPath(); ctx.arc(px, py, pr, 0, Math.PI*2); ctx.fill();
// Ring
ctx.strokeStyle = '#fde68a'; ctx.lineWidth = 4;
ctx.beginPath(); ctx.ellipse(px, py, pr*1.7, pr*0.35, 0.3, 0, Math.PI*2); ctx.stroke();
// Rakete (links, schräg)
ctx.save(); ctx.translate(W*0.2, H*0.6); ctx.rotate(-0.5);
ctx.fillStyle = '#e5e7eb';
ctx.fillRect(-W*0.025, -H*0.08, W*0.05, H*0.16);
// Spitze
ctx.fillStyle = '#dc2626'; ctx.beginPath();
ctx.moveTo(-W*0.025, -H*0.08); ctx.lineTo(0, -H*0.13); ctx.lineTo(W*0.025, -H*0.08); ctx.fill();
// Fenster
ctx.fillStyle = '#3b82f6'; ctx.beginPath(); ctx.arc(0, -H*0.03, W*0.012, 0, Math.PI*2); ctx.fill();
// Flossen
ctx.fillStyle = '#dc2626';
ctx.beginPath(); ctx.moveTo(-W*0.025, H*0.04); ctx.lineTo(-W*0.05, H*0.08); ctx.lineTo(-W*0.025, H*0.08); ctx.fill();
ctx.beginPath(); ctx.moveTo(W*0.025, H*0.04); ctx.lineTo(W*0.05, H*0.08); ctx.lineTo(W*0.025, H*0.08); ctx.fill();
// Flamme
ctx.fillStyle = '#fbbf24'; ctx.beginPath();
ctx.moveTo(-W*0.015, H*0.08); ctx.lineTo(0, H*0.16); ctx.lineTo(W*0.015, H*0.08); ctx.fill();
ctx.restore();
// Astronaut (Mitte unten)
ctx.fillStyle = '#fff'; ctx.beginPath(); ctx.arc(W*0.48, H*0.75, H*0.05, 0, Math.PI*2); ctx.fill(); // Helm
ctx.fillStyle = '#1f2937'; ctx.beginPath(); ctx.ellipse(W*0.48, H*0.75, H*0.03, H*0.025, 0, 0, Math.PI*2); ctx.fill(); // Visier
ctx.fillStyle = '#e5e7eb'; ctx.fillRect(W*0.45, H*0.78, W*0.06, H*0.1); // Körper
// UFO (oben links)
ctx.fillStyle = '#9ca3af'; ctx.beginPath(); ctx.ellipse(W*0.15, H*0.25, W*0.05, H*0.018, 0, 0, Math.PI*2); ctx.fill();
ctx.fillStyle = '#67e8f9'; ctx.beginPath(); ctx.ellipse(W*0.15, H*0.225, W*0.025, H*0.018, 0, Math.PI, 2*Math.PI); ctx.fill();
},
drawB(ctx, W, H) {
// Hintergrund: GLEICH wie A (kein Hintergrund-Unterschied)
ctx.fillStyle = '#0c0a2e'; ctx.fillRect(0, 0, W, H);
// Sterne — eine fehlt (UNTERSCHIED 1: nur 9 statt 10, der bei 0.48/0.25 fehlt)
ctx.fillStyle = '#fff';
const stars = [[0.10,0.15],[0.22,0.32],[0.35,0.10],[0.60,0.12],
[0.72,0.30],[0.85,0.18],[0.18,0.55],[0.90,0.50],[0.05,0.75]];
stars.forEach(([sx,sy])=>{ ctx.beginPath(); ctx.arc(sx*W, sy*H, 2, 0, Math.PI*2); ctx.fill(); });
// Planet (UNTERSCHIED 2: kein Ring)
const px = W*0.78, py = H*0.45, pr = H*0.13;
ctx.fillStyle = '#fb923c'; ctx.beginPath(); ctx.arc(px, py, pr, 0, Math.PI*2); ctx.fill();
// Rakete (UNTERSCHIED 3: keine Flamme)
ctx.save(); ctx.translate(W*0.2, H*0.6); ctx.rotate(-0.5);
ctx.fillStyle = '#e5e7eb';
ctx.fillRect(-W*0.025, -H*0.08, W*0.05, H*0.16);
ctx.fillStyle = '#dc2626'; ctx.beginPath();
ctx.moveTo(-W*0.025, -H*0.08); ctx.lineTo(0, -H*0.13); ctx.lineTo(W*0.025, -H*0.08); ctx.fill();
ctx.fillStyle = '#3b82f6'; ctx.beginPath(); ctx.arc(0, -H*0.03, W*0.012, 0, Math.PI*2); ctx.fill();
ctx.fillStyle = '#dc2626';
ctx.beginPath(); ctx.moveTo(-W*0.025, H*0.04); ctx.lineTo(-W*0.05, H*0.08); ctx.lineTo(-W*0.025, H*0.08); ctx.fill();
ctx.beginPath(); ctx.moveTo(W*0.025, H*0.04); ctx.lineTo(W*0.05, H*0.08); ctx.lineTo(W*0.025, H*0.08); ctx.fill();
ctx.restore();
// Astronaut (UNTERSCHIED 4: ROTER Anzug statt grau)
ctx.fillStyle = '#fff'; ctx.beginPath(); ctx.arc(W*0.48, H*0.75, H*0.05, 0, Math.PI*2); ctx.fill();
ctx.fillStyle = '#1f2937'; ctx.beginPath(); ctx.ellipse(W*0.48, H*0.75, H*0.03, H*0.025, 0, 0, Math.PI*2); ctx.fill();
ctx.fillStyle = '#dc2626'; ctx.fillRect(W*0.45, H*0.78, W*0.06, H*0.1);
// UFO (UNTERSCHIED 5: an anderer Position - weiter rechts oben)
ctx.fillStyle = '#9ca3af'; ctx.beginPath(); ctx.ellipse(W*0.42, H*0.15, W*0.05, H*0.018, 0, 0, Math.PI*2); ctx.fill();
ctx.fillStyle = '#67e8f9'; ctx.beginPath(); ctx.ellipse(W*0.42, H*0.125, W*0.025, H*0.018, 0, Math.PI, 2*Math.PI); ctx.fill();
},
spots: [
{ x: 0.48, y: 0.25, r: 0.05, label: 'Fehlender Stern' },
{ x: 0.78, y: 0.45, r: 0.13, label: 'Fehlender Ring' },
{ x: 0.21, y: 0.74, r: 0.06, label: 'Fehlende Flamme' },
{ x: 0.48, y: 0.83, r: 0.06, label: 'Anderer Anzug (rot)' },
{ x: 0.42, y: 0.15, r: 0.07, label: 'UFO an anderer Stelle' },
],
},
];
// Pro Aufruf andere Szene (rotiert) — so bekommt jeder Spielzug bei multi:3 eine neue Szene
let _sceneCounter = 0;
function run(wrap, W, H, cfg, onDone) {
const scene = SCENES[_sceneCounter % SCENES.length];
_sceneCounter++;
const theme = cfg.theme || { primary: '#84cc16' };
// Zwei Canvas nebeneinander
const halfW = Math.floor((W - 8) / 2);
const imgH = H - 64;
const container = document.createElement('div');
container.style.cssText = 'position:relative;width:100%;';
wrap.appendChild(container);
const canvasA = document.createElement('canvas');
canvasA.width = halfW; canvasA.height = imgH;
canvasA.style.cssText = `display:inline-block;border-radius:8px;cursor:default;`;
const canvasB = document.createElement('canvas');
canvasB.width = halfW; canvasB.height = imgH;
canvasB.style.cssText = `display:inline-block;border-radius:8px;cursor:crosshair;margin-left:8px;`;
container.appendChild(canvasA);
container.appendChild(canvasB);
// HUD-Canvas
const hud = document.createElement('canvas');
hud.width = W; hud.height = 48;
hud.style.display = 'block';
container.appendChild(hud);
const ctxA = canvasA.getContext('2d');
const ctxB = canvasB.getContext('2d');
const ctxH = hud.getContext('2d');
scene.drawA(ctxA, halfW, imgH);
scene.drawB(ctxB, halfW, imgH);
let found = new Set();
let marks = []; // { x, y, ok }
let stopped = false;
let endTimer;
function drawMarks() {
scene.drawB(ctxB, halfW, imgH); // neu zeichnen
marks.forEach(m => {
ctxB.strokeStyle = m.ok ? '#22c55e' : '#ef4444';
ctxB.lineWidth = 3;
ctxB.beginPath();
ctxB.arc(m.x, m.y, 18, 0, Math.PI * 2);
ctxB.stroke();
if (m.ok) {
ctxB.fillStyle = 'rgba(34,197,94,0.25)';
ctxB.fill();
}
});
}
function drawHUD() {
ctxH.clearRect(0, 0, W, 48);
MGAPI.text(ctxH, `🔍 ${found.size} / ${scene.spots.length} Unterschiede gefunden`, W/2, 16,
{ size: 13, color: theme.primary });
MGAPI.text(ctxH, 'Klicke auf die Unterschiede im rechten Bild', W/2, 36,
{ size: 11, color: 'rgba(255,255,255,0.4)' });
}
function hitsSpot(s, mx, my) {
if (s.shape === 'rect') {
const x = s.x * halfW, y = s.y * imgH;
const w = s.w * halfW, h = s.h * imgH;
return mx >= x && mx < x + w && my >= y && my < y + h;
}
const sx = s.x * halfW, sy = s.y * imgH;
const d = Math.sqrt((mx - sx) ** 2 + (my - sy) ** 2);
return d < s.r * Math.min(halfW, imgH);
}
canvasB.addEventListener('click', e => {
if (found.size >= scene.spots.length) return;
const rect = canvasB.getBoundingClientRect();
const mx = (e.clientX - rect.left) * (canvasB.width / rect.width / (window.devicePixelRatio || 1));
const my = (e.clientY - rect.top) * (canvasB.height / rect.height);
// Reihenfolge = Priorität: erste passende Spot gewinnt (radial-Spots vor rect-Catchall)
let hit = null;
for (let i = 0; i < scene.spots.length; i++) {
if (found.has(i)) continue;
if (hitsSpot(scene.spots[i], mx, my)) { hit = i; break; }
}
if (hit !== null) {
found.add(hit);
// Treffer-Marker an Klick-Position (statt Spot-Mitte) — funktioniert für Kreis UND Rechteck
marks.push({ x: mx, y: my, ok: true });
// Auch in Bild A markieren (gleiche Klick-Position)
ctxA.strokeStyle = '#22c55e';
ctxA.lineWidth = 3;
ctxA.beginPath(); ctxA.arc(mx, my, 18, 0, Math.PI * 2); ctxA.stroke();
ctxA.fillStyle = 'rgba(34,197,94,0.2)'; ctxA.fill();
} else {
marks.push({ x: mx, y: my, ok: false });
setTimeout(() => {
marks = marks.filter(m => m.ok);
drawMarks(); drawHUD();
}, 600);
}
drawMarks();
drawHUD();
if (found.size >= scene.spots.length && !endTimer) {
endTimer = setTimeout(() => onDone(true), 900);
// Overlay
ctxH.fillStyle = 'rgba(16,185,129,0.9)';
MGAPI.roundRect(ctxH, W/2-120, 4, 240, 38, 8, 'rgba(16,185,129,0.9)', null);
MGAPI.text(ctxH, '🎉 Alle Unterschiede gefunden!', W/2, 24,
{ size: 14, family: "'Fredoka One',cursive", color: '#fff' });
}
});
drawHUD();
return {
stop() {
stopped = true;
clearTimeout(endTimer);
},
};
}
function launch(wrap, W, H, cfg) { return run(wrap, W, H, cfg, won => MGAPI.onResult(won)); }
function preview(wrap, W, H, cfg) { return run(wrap, W, H, cfg, won => MGAPI.onResult(won)); }
return { id: ID, emoji: EMOJI, name: NAME, desc: DESC, controls: CONTROLS, multi: MULTI, launch, preview };
})();