Mini Apps and Mini Games

Portable Calculator for Study Breaks

Complete a portable calculator for break time scenarios: includes real content, interactive controls, clear state feedback, and responsive layouts across sizes.

Mini Apps and Mini GamesPortable calculatorHTMLCSSJavaScript
With JavaScript enabled, you can edit, run, and save this example. The fixed source is as follows:
<!doctype html>
<html lang="en" dir="ltr">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Portable Calculator for Study Breaks</title>
  <style>
    :root { --ink:#17241d; --paper:#f3f0e7; --accent:#af4f45; --secondary:#9eb49f; --line:color-mix(in srgb, var(--ink) 18%, transparent); --shadow:0 24px 60px color-mix(in srgb, var(--ink) 16%, transparent); color-scheme:light; }
    * { box-sizing:border-box; }
    html { min-width:320px; background:var(--paper); }
    body { min-height:100vh; margin:0; overflow-x:hidden; color:var(--ink); font-family:"Songti SC","Noto Serif SC",Georgia,serif; background:linear-gradient(90deg,transparent 49.7%,color-mix(in srgb,var(--ink) 7%,transparent) 50%,transparent 50.3%),var(--paper); }
    button,input,select,textarea { color:inherit; font:inherit; }
    button,[role="button"],input,select,textarea { accent-color:var(--accent); }
    button { cursor:pointer; }
    button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[tabindex]:focus-visible { outline:3px solid var(--accent); outline-offset:3px; }
    [hidden] { display:none !important; }
    @media (max-width:700px) { .mast h1 { line-height:1.08 !important; letter-spacing:-.035em !important; overflow-wrap:anywhere; } }
    @media (prefers-reduced-motion:reduce) { *,*::before,*::after { scroll-behavior:auto !important; animation-duration:.01ms !important; animation-iteration-count:1 !important; transition-duration:.01ms !important; } }
    .page{width:min(1180px,calc(100% - 40px));margin:auto;padding:7vw 0}.mast{display:grid;grid-template-columns:minmax(0,1.6fr) minmax(180px,.4fr);gap:5vw;align-items:end;margin-bottom:38px}.mast h1{font-family:"Songti SC",Georgia,serif;font-weight:800;font-size:clamp(42px,9vw,92px);max-width:920px;margin:0;line-height:.94}.eyebrow{display:block;margin-bottom:14px;color:var(--accent);font:800 11px/1 ui-monospace,monospace;letter-spacing:.24em}.intro{max-width:58ch;line-height:1.9}.scenario{align-self:start;padding-top:10px;border-top:1px solid var(--ink);font-style:italic}.demo{border-radius:0;border-width:2px;box-shadow:14px 14px 0 color-mix(in srgb,var(--ink) 18%,transparent);position:relative;overflow:hidden;min-height:420px;padding:clamp(22px,4vw,48px);background:var(--paper)}@media(max-width:700px){.page{width:calc(100% - 22px);padding:26px 0}.mast{grid-template-columns:1fr}.demo{min-height:340px;padding:18px}}
    .panel{padding:22px;border:1px solid var(--line);background:color-mix(in srgb,#fff 58%,transparent)}.stack{display:grid;gap:15px}.row{display:flex;flex-wrap:wrap;gap:10px;align-items:center}.action{min-height:44px;padding:10px 17px;border:1px solid var(--ink);border-radius:999px;background:transparent}.action.primary,.action.is-active{color:var(--paper);background:var(--accent)}.muted{opacity:.68}.status{min-height:24px;margin-top:15px;color:var(--accent);font-weight:800}.metric{font-size:clamp(30px,6vw,58px);font-weight:900}.meter{height:9px;overflow:hidden;border-radius:999px;background:color-mix(in srgb,var(--ink) 12%,transparent)}.meter>i{display:block;height:100%;background:var(--accent)}.chip{padding:6px 9px;border:1px solid var(--line);border-radius:999px;font-size:12px}
    .composition-split{display:grid;grid-template-columns:150px minmax(0,1fr);gap:18px;align-items:start}.split-note{position:sticky;top:20px;display:grid;gap:14px;padding:18px 12px;border-block:3px double var(--accent);font-size:13px;line-height:1.65}.split-note b{font:900 12px/1 ui-monospace,monospace;letter-spacing:.12em}.split-note span{writing-mode:vertical-rl;min-height:120px;color:color-mix(in srgb,var(--ink) 60%,transparent)}.composition-split .demo{min-width:0}@media(max-width:900px){.composition-split{grid-template-columns:1fr}.split-note{position:static;grid-template-columns:auto 1fr}.split-note span{writing-mode:horizontal-tb;min-height:0}}
    .calc-workbench{display:grid;grid-template-columns:minmax(280px,520px) minmax(220px,.7fr);gap:18px;justify-content:center}.mini{padding:22px;border:1px solid var(--line);border-radius:24px;background:var(--ink);color:var(--paper)}.calculator output{display:block;min-height:90px;padding:22px;text-align:right;font:800 clamp(34px,8vw,62px)/1 ui-monospace,monospace}.calc-keys{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}.calc-keys button{min-height:58px;border:1px solid rgba(255,255,255,.16);border-radius:14px;color:inherit;background:rgba(255,255,255,.08);font-size:20px}.calculator>.action{width:100%;margin-top:10px;color:inherit;border-color:rgba(255,255,255,.3)}.calc-ledger{padding:24px;border-block:3px double var(--accent)}.calc-ledger h2{margin:.5em 0}.calc-ledger ul{display:grid;gap:7px;padding-left:20px}.calc-ledger p{line-height:1.7}@media(max-width:720px){.calc-workbench{grid-template-columns:1fr}.calc-ledger{order:-1}}.workflow-session{display:grid;gap:14px}.session-command{display:grid;grid-template-columns:1fr auto minmax(170px,.45fr) auto;gap:16px;align-items:end;padding:18px;border-block:4px double var(--ink)}.session-command h2{margin:.2em 0}.session-command output{font:900 clamp(28px,5vw,54px)/1 ui-monospace,monospace}.session-command label{display:grid;grid-template-columns:1fr auto;gap:7px;font-size:12px}.session-command input{grid-column:1/-1;width:100%}#workflowSessionProgress{height:12px;overflow:hidden;border-radius:2px;background:var(--line)}#workflowSessionProgress i{display:block;width:0;height:100%;background:var(--accent)}.session-stage{min-width:0;transition:filter .25s,transform .25s}.session-stage[data-session-phase="running"]{transform:translateY(-3px)}.session-stage[data-session-phase="paused"]{filter:grayscale(.65)}.session-stage[data-session-phase="complete"]{filter:contrast(.78);opacity:.72}.session-log{display:grid;grid-template-columns:auto 1fr;gap:18px;align-items:start}.session-log ol{display:flex;flex-wrap:wrap;gap:7px;padding:0;margin:0;list-style:none}.session-log li{padding:5px 8px;border:1px solid var(--line);font-size:12px}@media(max-width:900px){.session-stage{order:-1}.session-command{grid-template-columns:1fr auto}.session-command label{grid-column:1/-1}.session-log{grid-template-columns:1fr}}
  </style>
</head>
<body data-aesthetic="editorial" data-composition="split-note">
  <main class="page">
    <header class="mast"><div><span class="eyebrow">editorial / Portable Calculator / INTERMEDIATE</span><h1>Portable Calculator for Study Breaks</h1><p class="intro">Complete a portable calculator for break time scenarios: includes real content, interactive controls, clear state feedback, and responsive layouts across sizes.</p></div><span class="scenario">Study Break</span></header>
    <div class="composition-split"><aside class="split-note"><b>CASE 02</b><span>Master the semantic structure, responsive layout, keyboard interaction, and state synchronization of a portable calculator.</span></aside><section class="demo" aria-label="Study Break Portable Calculator Interaction Area"><div class="workflow-session"><header class="session-command"><div><span class="eyebrow">Study Break SESSION</span><h2>Study Break Timer Console</h2></div><output id="workflowSessionClock">00:45</output><label>Round Duration<input id="workflowSessionLength" type="range" min="15" max="90" step="15" value="45"><span>sec</span></label><button id="workflowSessionToggle" class="action primary" type="button">Start Break</button></header><div id="workflowSessionProgress" role="progressbar" aria-label="Study Break Timer Progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><i></i></div><section id="workflowCore" class="workflow-core session-stage" data-session-phase="ready" tabindex="-1"><!-- 11DZ_CORE_START:mini-apps-games-calculator-pad --><div class="calc-workbench"><div class="mini calculator"><output id="calcDisplay" aria-live="polite">0</output><div class="calc-keys"><button type="button" data-key="7" data-core-bridge="mini-apps-games-calculator-pad">7</button><button type="button" data-key="8">8</button><button type="button" data-key="9">9</button><button type="button" data-key="÷">÷</button><button type="button" data-key="4">4</button><button type="button" data-key="5">5</button><button type="button" data-key="6">6</button><button type="button" data-key="×">×</button><button type="button" data-key="1">1</button><button type="button" data-key="2">2</button><button type="button" data-key="3">3</button><button type="button" data-key="−">−</button><button type="button" data-key="0">0</button><button type="button" data-key=".">.</button><button type="button" data-key="=">=</button><button type="button" data-key="+">+</button></div><button id="calcClear" class="action" type="button">Clear</button></div><aside class="calc-ledger"><span class="eyebrow">Class Break MEMO</span><h2>Study break calculator memo</h2><ul><li>Class break collaboration</li><li>Break-time progress</li><li>Class Break Reminder</li><li>Recess favorites</li><li>Study Break Overview</li><li>Recess plan</li></ul><p>The number keys, operators, and equals sign are handled by an explicit state machine.</p></aside></div><!-- 11DZ_CORE_END --></section><footer class="session-log"><strong id="workflowSessionScore">0 interaction checkpoints</strong><ol id="workflowSessionLaps" aria-label="Round Log"></ol></footer></div><p id="status" class="status" role="status" aria-live="polite"></p></section></div>
  </main>
  <script>
    'use strict';
    const statusOutput = document.querySelector('#status');
    const announce = message => { statusOutput.textContent = message; };
    /* 11DZ_CORE_SCRIPT_START:mini-apps-games-calculator-pad */
let current='0';let accumulator=null;let pendingOperator=null;let replaceCurrent=false;const display=document.querySelector('#calcDisplay');const calculator=document.querySelector('.calculator');const operations={'+':(left,right)=>left+right,'−':(left,right)=>left-right,'×':(left,right)=>left*right,'÷':(left,right)=>right===0?NaN:left/right};function renderCalculator(){display.textContent=current;}function resetCalculator(){current='0';accumulator=null;pendingOperator=null;replaceCurrent=false;renderCalculator();}function calculatePending(){if(pendingOperator===null||accumulator===null)return Number(current);const result=operations[pendingOperator](accumulator,Number(current));if(!Number.isFinite(result)){current='Error';accumulator=null;pendingOperator=null;replaceCurrent=true;return null;}current=String(Number(result.toFixed(10)));accumulator=Number(current);return accumulator;}function pressCalculatorKey(key){if(/^\d$/.test(key)){if(current==='Error'||replaceCurrent){current=key;replaceCurrent=false;}else if(current==='0')current=key;else current+=key;}else if(key==='.'){if(current==='Error'||replaceCurrent){current='0.';replaceCurrent=false;}else if(!current.includes('.'))current+='.';}else if(key in operations){if(current==='Error')resetCalculator();if(pendingOperator!==null&&!replaceCurrent)calculatePending();accumulator=Number(current);pendingOperator=key;replaceCurrent=true;}else if(key==='='){if(pendingOperator!==null&&calculatePending()!==null){pendingOperator=null;replaceCurrent=true;}}renderCalculator();announce(current==='Error'?'Unable to complete the calculation':'Calculation Result '+current);}document.querySelectorAll('[data-key]').forEach(button=>button.addEventListener('click',()=>pressCalculatorKey(button.dataset.key)));document.querySelector('#calcClear').addEventListener('click',()=>{resetCalculator();announce('Cleared');});document.addEventListener('keydown',event=>{if(!calculator.contains(document.activeElement))return;const keyboardMap={Enter:'=',Escape:'Clear','+':'+','-':'−','*':'×','/':'÷'};const key=keyboardMap[event.key]||event.key;if(key==='Clear'){event.preventDefault();resetCalculator();announce('Cleared');return;}if(/^\d$/.test(key)||['.','=','+','−','×','÷'].includes(key)){event.preventDefault();pressCalculatorKey(key);}});
/* 11DZ_CORE_SCRIPT_END */
const workflowBridgeSpec={"name":"mini-apps-games-calculator-pad","selector":"[data-core-bridge=\"mini-apps-games-calculator-pad\"]","mode":"press","key":" "};const workflowBridgeCore=document.querySelector('#workflowCore');const workflowBridgeControl=workflowBridgeCore.querySelector(workflowBridgeSpec.selector);if(!workflowBridgeControl)throw new Error('Missing core bridge: '+workflowBridgeSpec.name);const workflowBridgeControlledId=workflowBridgeControl.getAttribute('aria-controls');const workflowBridgeControlled=workflowBridgeControlledId?document.getElementById(workflowBridgeControlledId):null;workflowBridgeCore.dataset.workflowBridge=workflowBridgeSpec.name;workflowBridgeCore.dataset.workflowVersion='0';function workflowBridgeSerialize(){const visualNode=workflowBridgeCore.firstElementChild||workflowBridgeCore;const visual=getComputedStyle(visualNode);const outputs=[...workflowBridgeCore.querySelectorAll('output,[role="status"],[aria-live],meter,progress')].map(node=>node.textContent.trim()+'|'+node.getAttribute('aria-valuenow')+'|'+node.getAttribute('value'));const canvas=[...workflowBridgeCore.querySelectorAll('canvas')].map(node=>{try{return node.toDataURL().slice(-160);}catch{return 'canvas-unavailable';}});return JSON.stringify({html:workflowBridgeCore.innerHTML,status:statusOutput.textContent,outputs,canvas,visual:[visual.display,visual.visibility,visual.opacity,visual.transform,visual.filter,visual.backgroundColor,visual.width,visual.height],scroll:workflowBridgeSpec.mode==='scroll'?workflowBridgeControl.scrollTop:null});}let workflowBridgeLastEffect=workflowBridgeSerialize();function workflowBridgeSummary(){const label=(workflowBridgeControl.getAttribute('aria-label')||workflowBridgeControl.textContent||workflowBridgeControl.value||workflowBridgeSpec.name).trim().replace(/\s+/g,' ').slice(0,72);return label+' · Core Version '+workflowBridgeCore.dataset.workflowVersion;}function workflowBridgeCommit(){const effect=workflowBridgeSerialize();if(effect===workflowBridgeLastEffect)return {changed:false,summary:workflowBridgeSummary()};workflowBridgeLastEffect=effect;workflowBridgeCore.dataset.workflowVersion=String(Number(workflowBridgeCore.dataset.workflowVersion||0)+1);return {changed:true,summary:workflowBridgeSummary()};}function workflowBridgeScheduleCommit(){queueMicrotask(workflowBridgeCommit);setTimeout(workflowBridgeCommit,0);}workflowBridgeControl.addEventListener("click",workflowBridgeScheduleCommit);const workflowBridgeStateTargets=new Set(workflowBridgeCore.querySelectorAll('dialog'));if(workflowBridgeControlled&&workflowBridgeCore.contains(workflowBridgeControlled))workflowBridgeStateTargets.add(workflowBridgeControlled);workflowBridgeStateTargets.forEach(target=>['close','cancel','toggle'].forEach(eventName=>target.addEventListener(eventName,workflowBridgeScheduleCommit)));function workflowBridgeActivate(){workflowBridgeControl.focus();workflowBridgeControl.click();const result=workflowBridgeCommit();setTimeout(workflowBridgeCommit,0);return result;}function workflowBridgeReset(){workflowBridgeCore.dataset.workflowVersion='0';workflowBridgeLastEffect=workflowBridgeSerialize();}
const workflowSessionCore=document.querySelector('#workflowCore');const workflowSessionToggle=document.querySelector('#workflowSessionToggle');const workflowSessionLength=document.querySelector('#workflowSessionLength');const workflowSessionState={phase:'ready',elapsed:0,limit:Number(workflowSessionLength.value),checkpoints:[],timer:null};function workflowSessionFormat(seconds){return String(Math.floor(seconds/60)).padStart(2,'0')+':'+String(seconds%60).padStart(2,'0');}function workflowSessionDrive(){const percent=Math.min(100,Math.round(workflowSessionState.elapsed/workflowSessionState.limit*100));document.querySelector('#workflowSessionClock').textContent=workflowSessionFormat(Math.max(0,workflowSessionState.limit-workflowSessionState.elapsed));const progress=document.querySelector('#workflowSessionProgress');progress.setAttribute('aria-valuenow',String(percent));progress.querySelector('i').style.width=percent+'%';workflowSessionCore.dataset.sessionPhase=workflowSessionState.phase;document.querySelector('#workflowSessionScore').textContent=workflowSessionState.checkpoints.length+' interactive checkpoints';}function workflowSessionLap(label){workflowSessionState.checkpoints.push({label,at:workflowSessionState.elapsed});const item=document.createElement('li');item.textContent=label+' · '+workflowSessionFormat(workflowSessionState.elapsed);document.querySelector('#workflowSessionLaps').append(item);workflowSessionDrive();}function workflowSessionStop(complete=false){clearInterval(workflowSessionState.timer);workflowSessionState.timer=null;workflowSessionState.phase=complete?'complete':'paused';workflowSessionToggle.textContent=complete?'Restart':'Continue round';workflowSessionToggle.setAttribute('aria-pressed','false');workflowSessionDrive();announce(complete?'Round complete for the study break timer':'Round paused');}function workflowSessionStart(){if(workflowSessionState.phase==='complete'){workflowSessionState.elapsed=0;workflowSessionState.checkpoints=[];document.querySelector('#workflowSessionLaps').replaceChildren();}workflowSessionState.phase='running';workflowSessionToggle.textContent='Pause round';workflowSessionToggle.setAttribute('aria-pressed','true');const bridge=workflowBridgeActivate();workflowSessionLap(bridge.summary);clearInterval(workflowSessionState.timer);workflowSessionState.timer=setInterval(()=>{workflowSessionState.elapsed+=1;if(workflowSessionState.elapsed>=workflowSessionState.limit){workflowSessionStop(true);return;}workflowSessionDrive();},1000);workflowSessionDrive();announce('Class Break Timer Round Started · '+bridge.summary);}workflowSessionToggle.addEventListener('click',()=>workflowSessionState.phase==='running'?workflowSessionStop():workflowSessionStart());workflowSessionLength.addEventListener('input',()=>{workflowSessionState.limit=Number(workflowSessionLength.value);workflowSessionState.elapsed=Math.min(workflowSessionState.elapsed,workflowSessionState.limit);workflowSessionDrive();});workflowSessionCore.addEventListener('keydown',event=>{if(event.key==='Enter'||event.key===' '){workflowSessionLap('Keyboard Interaction');}});workflowSessionCore.addEventListener('click',event=>{if(event.target.closest('[data-core-bridge]'))workflowSessionLap('Core action · '+workflowBridgeSummary());});document.addEventListener('visibilitychange',()=>{if(document.hidden&&workflowSessionState.phase==='running')workflowSessionStop();});workflowSessionDrive();
workflowBridgeReset();
  </script>
</body>
</html>
Page feedbackFound an issue or have suggestions for improvement?
Feedback features need to be used in the online version

Please enable JavaScript in the online version before submitting; local features of the current tool or example are not affected.

Go to the online version for feedback