This jam is now over. It ran from 2025-09-25 14:47:00 to 2025-09-26 14:46:00. View results
Game concept / prompt (displayed in-game):
"You're Max — a super-searcher on a mission inside and around your home. Objects are hidden across rooms (living room, bedroom, laundry, garden) while you do everyday activities: washing clothes, reading, playing videos, dancing, cutting grass, trimming trees. Your job: SEARCH the scene, FIND hidden tasks or objects, COMPLETE mini-challenges, and rack up points before the timer runs out. Each found object gives clues to the final 'Master Object' — find all pieces to win!"
Features included in this single file:
- Interactive clickable rooms and hotspots
- Randomly placed hidden objects from a pool of activities (washing, reading, dancing, etc.)
- Mini-challenges: quick typing, click-speed, simple puzzle
- Levels (increase difficulty and timer changes)
- Score, timer, hints, sounds (browser audio using simple oscillator), responsive layout
- Easy to extend: change object list, room backgrounds, timers.
How to use:
1. Save this file as "max-search-game.html" on your machine.
2. Open it in Chrome, Firefox, Safari, or Edge.
3. Play! Mobile supported (best in landscape).
-->
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Max Search Game</title>
<style>
:root{--bg:#f4f7fb;--card:#ffffff;--accent:#5a9bd8;--muted:#6b7280}
html,body{height:100%;margin:0;font-family:Inter,ui-sans-serif,system-ui,Segoe UI,Roboto,'Helvetica Neue',Arial}
body{background:linear-gradient(180deg,#eaf2ff, #f4f7fb);display:flex;align-items:center;justify-content:center;padding:18px}
.app{width:100%;max-width:1100px;background:var(--card);box-shadow:0 12px 30px rgba(23,43,77,.08);border-radius:14px;overflow:hidden}
header{display:flex;align-items:center;justify-content:space-between;padding:18px 22px;border-bottom:1px solid rgba(15,23,42,0.04)}
h1{font-size:20px;margin:0;color:#0f172a}
.controls{display:flex;gap:10px;align-items:center}
button{background:var(--accent);color:#fff;border:0;padding:8px 12px;border-radius:10px;cursor:pointer;font-weight:600}
button.secondary{background:transparent;color:var(--accent);border:1px solid rgba(90,155,216,.18)}
.game-wrap{display:grid;grid-template-columns:1fr 320px;gap:12px;padding:18px}
.scene{background:linear-gradient(180deg,#ffffff,#f6fbff);border-radius:10px;padding:14px;min-height:520px;position:relative;overflow:hidden}
.rooms{display:grid;grid-template-columns:repeat(2,1fr);gap:12px;height:100%}
.room{background:linear-gradient(180deg,#fcfeff,#eef7ff);border-radius:10px;padding:10px;position:relative;overflow:hidden;border:1px solid rgba(11,65,120,0.04)}
.room .label{position:absolute;left:10px;top:8px;font-size:12px;color:var(--muted)}
.hotspot{position:absolute;border-radius:8px;padding:6px 8px;background:rgba(255,255,255,0.92);box-shadow:0 6px 18px rgba(12,30,50,0.06);cursor:pointer;transition:transform .12s;border:1px dashed rgba(90,155,216,0.18);font-size:12px}
.hotspot:active{transform:scale(.98)}
.hud{display:flex;flex-direction:column;gap:10px}
.panel{background:linear-gradient(180deg,#fff,#fbfdff);border-radius:10px;padding:12px;border:1px solid rgba(12,30,50,0.04)}
.stat{display:flex;justify-content:space-between;align-items:center}
.list{display:flex;flex-direction:column;gap:8px}
.object{display:flex;gap:8px;align-items:center}
.badge{background:var(--accent);color:#fff;padding:6px 8px;border-radius:8px;font-weight:700}
.hint{font-size:13px;color:var(--muted)}
.footer{padding:12px 18px;border-top:1px solid rgba(15,23,42,0.04);display:flex;justify-content:space-between;align-items:center}
.toast{position:fixed;right:20px;bottom:20px;background:#111827;color:#fff;padding:10px 14px;border-radius:10px;box-shadow:0 14px 40px rgba(2,6,23,0.45)}
/* Mini-challenge modal */
.modal{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(8,12,20,0.45);z-index:50}
.modal-card{background:#fff;padding:20px;border-radius:12px;max-width:520px;width:95%;box-shadow:0 18px 50px rgba(2,6,23,0.3)}
input[type=text]{width:100%;padding:10px;border-radius:8px;border:1px solid #e6eefc}
.grid-rows{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}
.small{font-size:13px}
@media (max-width:880px){.game-wrap{grid-template-columns:1fr;}.scene{min-height:420px}.rooms{grid-template-columns:1fr}}
</style>
</head>
<body>
<div class="app" role="application" aria-label="Max Search Game">
<header>
<h1>Max Search Game</h1>
<div class="controls">
<div class="hint">Level: <strong id="level">1</strong></div>
<div class="hint">Time: <strong id="time">--</strong></div>
<button id="startBtn">Start Game</button>
<button id="hintBtn" class="secondary">Use Hint</button>
</div>
</header>
<div class="game-wrap">
<main class="scene" id="scene">
<div style="display:flex;gap:12px;height:100%">
<div class="rooms" id="rooms">
<div class="room" id="living" data-room="Living Room">
<div class="label">Living Room</div>
</div>
<div class="room" id="bedroom" data-room="Bedroom">
<div class="label">Bedroom</div>
</div>
<div class="room" id="laundry" data-room="Laundry">
<div class="label">Laundry / Utility</div>
</div>
<div class="room" id="garden" data-room="Garden">
<div class="label">Garden / Yard</div>
</div>
</div>
</div>
<div style="position:absolute;right:18px;top:18px;text-align:right;max-width:260px">
<div class="panel">
<div class="stat"><div>Score</div><div class="badge" id="score">0</div></div>
<hr />
<div class="hint" id="promptText">Prompt will show here when game starts.</div>
</div>
</div>
</main>
<aside class="hud">
<div class="panel">
<div style="display:flex;justify-content:space-between;align-items:center">
<div><strong>Tasks</strong></div>
<div class="hint">Found <span id="foundCount">0</span>/<span id="totalCount">0</span></div>
</div>
<div class="list" id="taskList"></div>
</div>
<div class="panel">
<div><strong>Inventory / Clues</strong></div>
<div class="list" id="inventory"></div>
</div>
<div class="panel">
<div style="display:flex;justify-content:space-between;align-items:center"><div><strong>Controls</strong></div></div>
<div style="margin-top:8px;display:flex;gap:8px;flex-wrap:wrap">
<button id="pauseBtn" class="secondary">Pause</button>
<button id="restartBtn" class="secondary">Restart</button>
</div>
</div>
<div class="panel">
<strong>How to play</strong>
<div class="hint" style="margin-top:8px">Click rooms to reveal hotspots. Complete mini-challenges to mark tasks done. Use hints if you're stuck. Find all task pieces to unlock the Master Object!</div>
</div>
</aside>
</div>
<div class="footer">
<div class="hint">Made for fun — Max Search Game</div>
<div class="hint">Created: Sep 2025</div>
</div>
</div>
<div id="modalRoot" style="display:none"></div>
<div id="toast" style="display:none" class="toast">Hello</div>
<script>
// Game data and logic
const OBJECTS = [
{id:'wash', name:'Washing Clothes', room:'laundry', desc:'A basket of damp clothes', points:30},
{id:'read', name:'Reading Book', room:'bedroom', desc:'A thick textbook with notes', points:20},
{id:'video', name:'Playing Video', room:'living', desc:'TV playing a video', points:15},
{id:'dance', name:'Dancing', room:'living', desc:'A pair of dancing shoes', points:18},
{id:'grass', name:'Cutting Grass', room:'garden', desc:'A grass pile / trimmer', points:25},
{id:'tree', name:'Cutting Tree', room:'garden', desc:'A pruned branch', points:25},
{id:'phone', name:'Phone Charger', room:'bedroom', desc:'Charger near the bed', points:10},
{id:'note', name:'Hidden Note', room:'living', desc:'A sticky note with clue', points:8}
];
// Configurable
let state = {
level:1,
timeLeft:90,
running:false,
score:0,
found:[],
tasks:[],
timerId:null,
paused:false
};
const roomsEl = document.getElementById('rooms');
const startBtn = document.getElementById('startBtn');
const hintBtn = document.getElementById('hintBtn');
const scoreEl = document.getElementById('score');
const taskListEl = document.getElementById('taskList');
const promptTextEl = document.getElementById('promptText');
const timeEl = document.getElementById('time');
const foundCount = document.getElementById('foundCount');
const totalCount = document.getElementById('totalCount');
const inventoryEl = document.getElementById('inventory');
const levelEl = document.getElementById('level');
const pauseBtn = document.getElementById('pauseBtn');
const restartBtn = document.getElementById('restartBtn');
const modalRoot = document.getElementById('modalRoot');
const toast = document.getElementById('toast');
function shuffle(a){for(let i=a.length-1;i>0;i--){const j=Math.floor(Math.random()*(i+1));[a[i],a[j]]=[a[j],a[i]]}return a}
function showToast(txt,ms=2000){toast.style.display='block';toast.textContent=txt;clearTimeout(toast._t);toast._t=setTimeout(()=>toast.style.display='none',ms)}
// Sound helper using WebAudio
const audioCtx = (window.AudioContext||window.webkitAudioContext) ? new (window.AudioContext||window.webkitAudioContext)() : null;
function beep(f=440,d=0.08){if(!audioCtx) return; const o=audioCtx.createOscillator(); const g=audioCtx.createGain(); o.connect(g); g.connect(audioCtx.destination); o.type='sine'; o.frequency.value=f; g.gain.value=0.05; o.start(); g.gain.exponentialRampToValueAtTime(0.0001,audioCtx.currentTime+d); setTimeout(()=>o.stop(),d*1000+50);}
function placeHotspots(tasks){
// Clear existing hotspots
document.querySelectorAll('.hotspot').forEach(n=>n.remove());
// For each task, create a hotspot in its room at a random position
const roomEls = {
living:document.getElementById('living'),
bedroom:document.getElementById('bedroom'),
laundry:document.getElementById('laundry'),
garden:document.getElementById('garden')
};
tasks.forEach(t=>{
const rEl = roomEls[t.room];
if(!rEl) return;
const el = document.createElement('div');
el.className='hotspot';
el.textContent=t.name.split(' ')[0];
el.style.left = (10 + Math.random()*75) + '%';
el.style.top = (10 + Math.random()*75) + '%';
el.dataset.id = t.id;
el.title = t.desc;
el.addEventListener('click', onHotspotClick);
rEl.appendChild(el);
});
}
function buildTaskUI(tasks){
taskListEl.innerHTML='';
tasks.forEach(t=>{
const row = document.createElement('div'); row.className='object';
row.innerHTML = `<div>${t.name}</div><div style="margin-left:auto;color:var(--muted)">${t.points} pts</div>`;
taskListEl.appendChild(row);
});
totalCount.textContent = tasks.length;
}
function startGame(){
state.found=[]; state.score=0; state.paused=false;
state.level = parseInt(levelEl.textContent) || 1;
// choose tasks based on level: higher levels include more tasks
const pool = shuffle(OBJECTS.slice());
const pickCount = Math.min(pool.length, 3 + state.level);
state.tasks = pool.slice(0,pickCount);
state.timeLeft = Math.max(40, 90 - state.level*8);
buildTaskUI(state.tasks);
placeHotspots(state.tasks);
updateHUD();
promptTextEl.textContent = `You're Max. Search the house and yard for ${pickCount} tasks. Complete mini-challenges to collect them!`;
startTimer();
state.running = true;
showToast('Game started — good luck!');
beep(880,0.06);
}
function updateHUD(){
scoreEl.textContent = state.score;
foundCount.textContent = state.found.length;
levelEl.textContent = state.level;
timeEl.textContent = formatTime(state.timeLeft);
}
function formatTime(s){ const m = Math.floor(s/60); const sec = s%60; return `${m}:${sec.toString().padStart(2,'0')}`; }
function startTimer(){ stopTimer(); state.timerId = setInterval(()=>{
if(state.paused) return;
state.timeLeft--;
if(state.timeLeft<=0){state.timeLeft=0; updateHUD(); endGame(false);}
updateHUD();
},1000);
}
function stopTimer(){ if(state.timerId) clearInterval(state.timerId); state.timerId=null; }
function endGame(win){ stopTimer(); state.running=false; if(win){ showModal(`<h3>Victory!</h3><p>You found all tasks and assembled the Master Object. Score: ${state.score}</p><div style="text-align:right"><button id=closeWin>Close</button></div>`); beep(1200,0.16); } else { showModal(`<h3>Time's up</h3><p>You scored ${state.score}. Try again to beat your score!</p><div style="text-align:right"><button id=closeLose>Close</button></div>`); beep(220,0.16); } }
function onHotspotClick(e){
const id = e.currentTarget.dataset.id;
if(state.found.includes(id)) { showToast('Already collected'); return; }
// launch a mini-challenge depending on object
const obj = state.tasks.find(x=>x.id===id);
if(!obj) return;
if(Math.random()<0.35){ launchTypingChallenge(obj); }
else if(Math.random()<0.7){ launchClickSpeed(obj); }
else { launchPuzzle(obj); }
}
// Mini-challenges
function launchTypingChallenge(obj){
const word = obj.name.split(' ').slice(0,2).join('').toLowerCase();
showModal(`<h3>Typing Speed</h3><p class=small>Type the word <strong>${word}</strong> within 6 seconds to collect <strong>${obj.points}</strong> pts.</p><input id=typeInput placeholder='type here' autocomplete=off /><div style=text-align:right;margin-top:10px><button id=typeSubmit>Submit</button></div>`);
const input = document.getElementById('typeInput'); input.focus();
let timeLeft=6; const tInt = setInterval(()=>{timeLeft--; if(timeLeft<=0){clearInterval(tInt); closeModal(); showToast('Too slow!');}},1000);
document.getElementById('typeSubmit').onclick = ()=>{
clearInterval(tInt);
const val = input.value.trim().toLowerCase(); closeModal(); if(val===word){ collectObject(obj); } else { showToast('Incorrect'); }
};
}
function launchClickSpeed(obj){
// click a moving target N times in time limit
const targetCount = Math.max(6, Math.floor(8 - state.level/2));
let clicked=0; let timeLeft=5 + Math.floor(state.level/2);
showModal(`<h3>Click Speed</h3><p class=small>Click the button <strong>${targetCount}</strong> times before time runs out.</p><div style="display:flex;justify-content:center;margin:14px"><button id=fastBtn>0</button></div><div style=text-align:right><button id=stopFast>Give up</button></div>`);
const btn = document.getElementById('fastBtn'); btn.onclick = ()=>{ clicked++; btn.textContent = clicked; if(clicked>=targetCount){ closeModal(); collectObject(obj); } };
const stopFast = document.getElementById('stopFast'); stopFast.onclick = ()=>{ closeModal(); showToast('Challenge abandoned'); };
const tInt = setInterval(()=>{ timeLeft--; if(timeLeft<=0){ clearInterval(tInt); closeModal(); showToast('Time over'); } },1000);
}
function launchPuzzle(obj){
// simple sliding selection: choose correct image/text
const options = shuffle([obj.name, 'Fake Object', 'Nothing', 'Reminder']).slice(0,3);
showModal(`<h3>Choose Correct</h3><p class=small>Pick the correct item to collect <strong>${obj.points}</strong> pts.</p><div class=grid-rows>${options.map((o,i)=>`<button class=opt data-i=${i}>${o}</button>`).join('')}</div><div style=text-align:right;margin-top:8px><button id=skipPuzzle>Skip</button></div>`);
document.querySelectorAll('.opt').forEach(b=>b.onclick = (ev)=>{ const val = ev.currentTarget.textContent; closeModal(); if(val===obj.name){ collectObject(obj); } else { showToast('Wrong choice'); } });
document.getElementById('skipPuzzle').onclick = ()=>{ closeModal(); showToast('Skipped'); };
}
function collectObject(obj){
if(state.found.includes(obj.id)) return;
state.found.push(obj.id);
state.score += obj.points + Math.floor(Math.random()*6);
// push a clue to inventory
const li = document.createElement('div'); li.className='object'; li.textContent = `${obj.name} — clue: ${obj.desc}`;
inventoryEl.appendChild(li);
// remove hotspot UI marker
const hs = document.querySelector(`.hotspot[data-id='${obj.id}']`); if(hs) hs.style.display='none';
updateHUD(); beep(600,0.06);
showToast(`Collected: ${obj.name} (+${obj.points})`);
// Win condition — all found
if(state.found.length >= state.tasks.length){ endGame(true); }
}
// Modal helpers
function showModal(html){ modalRoot.style.display='block'; modalRoot.innerHTML = `<div class=modal><div class=modal-card>${html}</div></div>`;
// attach close listener via delegation
modalRoot.querySelector('.modal').addEventListener('click', function(e){ if(e.target===this){ closeModal(); } });
// attach close buttons
const closeBtns = modalRoot.querySelectorAll('button[id^=close], button[id^=skipPuzzle], button[id^=closeWin], button[id^=closeLose]');
closeBtns.forEach(b=>b.onclick = closeModal);
}
function closeModal(){ modalRoot.style.display='none'; modalRoot.innerHTML=''; }
// UI actions
startBtn.addEventListener('click', ()=>{ if(!state.running) startGame(); else { state.level++; startGame(); } });
hintBtn.addEventListener('click', ()=>{ if(!state.tasks || state.tasks.length===0) return; // reveal a random unfound
const unf = state.tasks.filter(t=>!state.found.includes(t.id)); if(unf.length===0) return; const pick = unf[Math.floor(Math.random()*unf.length)]; showToast(`Hint: Look in ${capitalize(pick.room)} — ${pick.desc}`); state.score = Math.max(0,state.score-5); updateHUD(); });
pauseBtn.addEventListener('click', ()=>{ state.paused = !state.paused; pauseBtn.textContent = state.paused ? 'Resume' : 'Pause'; showToast(state.paused ? 'Paused' : 'Resumed'); });
restartBtn.addEventListener('click', ()=>{ if(confirm('Restart game?')) startGame(); });
function capitalize(s){ return s.charAt(0).toUpperCase()+s.slice(1); }
// initial setup
(function init(){ levelEl.textContent = state.level; promptTextEl.textContent = 'Press Start to begin your Max Search adventure.'; updateHUD(); })();
// Expose simple keyboard shortcuts
window.addEventListener('keydown', (e)=>{
if(e.key==='h') hintBtn.click();
if(e.key===' ' && !state.running) startBtn.click();
});
</script>
</body>
</html>