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>