計算機 * { margin:0; padding:0; box-sizing:border-box; -webkit-tap-highlight-color:transparent; } :root { --bg:#000000; --btn-num:#333333; --btn-func:#a5a5a5; --btn-op:#ff9f0a; --btn-equal:#ff9f0a; --text-main:#ffffff; --text-op:#ffffff; --text-func:#000000; --text-display:#ffffff; --text-expr:#888888; --cursor:#ff9f0a; --divider:#222222; --shadow:rgba(0,0,0,0.4); } html,body { height:100%; background:var(--bg); font-family:-apple-system,'SF Pro Display','Helvetica Neue',sans-serif; overflow:hidden; touch-action:manipulation; } #app { display:flex; flex-direction:column; height:100dvh; max-width:480px; margin:0 auto; background:var(--bg); position:relative; transition:filter 0.3s; } /* ── 鎖定遮罩 ── */ #lock-overlay { display:none; position:absolute; inset:0; z-index:50; background:rgba(0,0,0,0.0); /* 攔截所有觸控 */ } body.locked #lock-overlay { display:block; } body.locked #app { filter:brightness(0.75); } /* ── 顯示區 ── */ #display-area { flex:1; display:flex; flex-direction:column; justify-content:flex-end; align-items:flex-end; padding:0 24px 12px; min-height:0; } #top-expr { font-size:18px; color:var(--text-expr); margin-bottom:2px; min-height:24px; text-align:right; width:100%; letter-spacing:0.2px; } #display-row { display:flex; align-items:flex-end; justify-content:flex-end; width:100%; } #display-num { font-size:80px; font-weight:200; color:var(--text-display); letter-spacing:-3px; line-height:1; transition:font-size 0.1s; text-align:right; word-break:break-all; } #cursor { display:none; } @keyframes blink { 0%,100%{opacity:1} 50%{opacity:0} } /* ── 工具列 ── */ #toolbar { display:flex; justify-content:space-between; align-items:center; padding:6px 18px; } .tool-btn { width:44px; height:44px; display:flex; align-items:center; justify-content:center; cursor:pointer; border:none; background:transparent; } .tool-btn svg { width:26px; height:26px; } #backspace-btn { background:transparent; border:none; width:44px; height:44px; display:flex; align-items:center; justify-content:center; cursor:pointer; padding:0; } #backspace-btn svg { width:30px; height:24px; } #backspace-btn:active { opacity:0.5; } #divider { display:none; } #divider { height:1px; background:var(--divider); } /* ── 按鈕區 ── */ #btn-area { padding:8px 12px 24px; display:flex; flex-direction:column; gap:12px; } .btn-row { display:flex; justify-content:space-between; gap:12px; } .btn { flex:1; aspect-ratio:1; border-radius:50%; border:none; cursor:pointer; font-size:32px; font-weight:400; display:flex; align-items:center; justify-content:center; user-select:none; -webkit-user-select:none; box-shadow:none; transition:transform 0.08s, opacity 0.08s, box-shadow 0.2s; color:var(--text-main); background:var(--btn-num); } .btn:active { transform:scale(0.93); opacity:0.7; } .btn.func { background:var(--btn-func); color:var(--text-func); font-size:26px; font-weight:500; } .btn.op { background:var(--btn-op); color:var(--text-op); font-size:32px; font-weight:400; } .btn.equal { background:var(--btn-equal); color:var(--text-op); font-size:32px; } .btn.small-text { font-size:22px; } #btn-add.holding { box-shadow:0 0 0 3px #ffffff; } #btn-0.holding { box-shadow:0 0 0 3px #e91e8c; } /* ── 設定 Modal ── */ #settings-overlay { display:none; position:fixed; inset:0; background:rgba(0,0,0,0.5); z-index:100; align-items:flex-end; justify-content:center; } #settings-overlay.open { display:flex; } #settings-panel { background:#f5f5f5; width:100%; max-width:480px; border-radius:20px 20px 0 0; padding:20px 20px 36px; animation:slideUp 0.3s ease; max-height:92dvh; overflow-y:auto; } @keyframes slideUp { from{transform:translateY(100%)} to{transform:translateY(0)} } #settings-panel h2 { font-size:18px; font-weight:700; color:#1a1a1a; margin-bottom:14px; text-align:center; } .tab-row { display:flex; margin-bottom:16px; border-radius:10px; overflow:hidden; border:2px solid var(--btn-equal); } .tab-btn { flex:1; padding:10px 4px; border:none; cursor:pointer; font-size:12px; font-weight:600; background:#fff; color:#888; transition:background 0.15s,color 0.15s; } .tab-btn.active { background:var(--btn-equal); color:#fff; } .tab-content { display:none; } .tab-content.active { display:block; } .setting-label { font-size:13px; color:#888; margin-bottom:8px; } .setting-row { display:flex; align-items:center; gap:10px; margin-bottom:14px; } .setting-input { flex:1; font-size:34px; font-weight:300; color:#1a1a1a; border:none; border-bottom:2.5px solid var(--btn-equal); background:transparent; text-align:center; padding-bottom:4px; outline:none; } #custom-input { border-bottom-color:#e91e8c; letter-spacing:3px; } .setting-unit { font-size:18px; color:#888; } .preview-box { border-radius:12px; padding:14px; text-align:center; margin-bottom:14px; } .preview-box.dark { background:#1a1a1a; } .preview-box.pink-bg { background:#1a0812; } .preview-label { font-size:12px; color:#aaa; margin-bottom:6px; } .preview-value { font-size:20px; font-weight:600; letter-spacing:2px; font-family:monospace; } .preview-value.green { color:var(--btn-equal); } .preview-value.pink { color:#e91e8c; } .quick-row { display:flex; gap:8px; margin-bottom:16px; } .quick-btn { flex:1; padding:10px 4px; border-radius:8px; border:2px solid transparent; background:#fff; font-size:13px; font-weight:500; color:#555; cursor:pointer; text-align:center; } .quick-btn.active { border-color:var(--btn-equal); background:#e8fdf0; color:var(--btn-equal); font-weight:700; } .save-btn { width:100%; padding:15px; color:white; border:none; border-radius:12px; font-size:17px; font-weight:700; cursor:pointer; letter-spacing:0.5px; margin-bottom:10px; } .save-btn.green { background:var(--btn-equal); } .save-btn.green:active { background:#17a045; } .save-btn.pink { background:#e91e8c; } .save-btn.pink:active { background:#c2185b; } #close-btn { width:100%; padding:10px; background:transparent; color:#888; border:none; font-size:15px; cursor:pointer; } .hint-box { background:#fff8e1; border-left:4px solid #ffc107; border-radius:8px; padding:12px; margin-bottom:14px; font-size:12px; color:#795548; line-height:1.8; } .badge { display:inline-block; padding:1px 7px; border-radius:20px; font-size:11px; font-weight:700; } .badge.green { background:#e8fdf0; color:var(--btn-equal); } .badge.pink { background:#fce4ec; color:#e91e8c; } .note { font-size:11px; color:#bbb; margin-top:6px; } hr.sep { border:none; border-top:1px solid #e0e0e0; margin:14px 0; }
0

🎩 後台設定

模式一 長按「+」3秒 → 時間預言,自動鎖定 X 秒後解鎖
模式二 長按「0」3秒 → 自訂數字預言,同樣自動解鎖
連按「=」5次(3秒內)→ 開啟此設定頁

觸發後幾分鐘顯示「此時此刻」

分鐘
⏱ 若現在觸發,目標數字為:

鎖定後幾秒自動解鎖

輸入你想要觀眾最後看到的數字

🎂 觸發後觀眾最終會看到:

*輸入什麼數字,觀眾按 = 後就會看到什麼



// ══ 狀態 ══ let display='0', topExpr='', accumulator=0; let pendingOp=null, waitNext=false, justEqual=false; let offsetMinutes=parseInt(localStorage.getItem('magic_offset')||'30'); let customTarget=localStorage.getItem('magic_custom')||''; let lockSeconds=parseInt(localStorage.getItem('magic_lock_seconds')||'15'); let isLocked=false; let lockTimer=null; let eqCount=0, eqTimer=null; const EQ_SECRET=5, EQ_TIMEOUT=3000, HOLD_MS=3000; const elNum=document.getElementById('display-num'); const elExpr=document.getElementById('top-expr'); const elAdd=document.getElementById('btn-add'); const elZero=document.getElementById('btn-0'); const overlay=document.getElementById('settings-overlay'); function render() { elNum.textContent=display; elExpr.textContent=topExpr; const l=display.length; elNum.style.fontSize=l>11?'34px':l>8?'48px':l>5?'60px':'68px'; } // ══ 鎖定 / 解鎖 ══ function lock(showMagicFn) { isLocked=true; document.body.classList.add('locked'); if(lockTimer) clearTimeout(lockTimer); // 等 X 秒後顯示魔術數字,並立刻解鎖 lockTimer=setTimeout(()=>{ if(!isLocked) return; showMagicFn(); if(navigator.vibrate) navigator.vibrate(40); unlock(); // 魔術數字出現後立刻解鎖,讓觀眾自己按 }, lockSeconds*1000); } function unlock() { isLocked=false; document.body.classList.remove('locked'); if(lockTimer){ clearTimeout(lockTimer); lockTimer=null; } } // ══ 計算機邏輯 ══ function applyOp(a,op,b){ return op==='+'?a+b:op==='−'?a-b:op==='×'?a*b:op==='÷'?(b?a/b:0):b; } function fmt(n){ if(isNaN(n)||!isFinite(n))return'Error'; if(Math.abs(n)>=1e12)return n.toExponential(4); return String(parseFloat(n.toPrecision(12))); } function handleDigit(d) { if(isLocked)return; if(justEqual){ display=d; topExpr=''; accumulator=0; pendingOp=null; waitNext=false; justEqual=false; render(); return; } if(waitNext){ display=d; waitNext=false; } else{ display=display==='0'?d:display.length>=13?display:display+d; } justEqual=false; render(); } function handleDot() { if(isLocked)return; if(waitNext){ display='0.'; waitNext=false; render(); return; } if(!display.includes('.')){ display+='.'; render(); } } function handleOp(op) { if(isLocked)return; const cur=parseFloat(display); if(pendingOp&&!waitNext){ const r=applyOp(accumulator,pendingOp,cur); display=fmt(r); accumulator=r; topExpr=display+' '+op; } else{ accumulator=cur; topExpr=fmt(cur)+' '+op; } pendingOp=op; waitNext=true; justEqual=false; render(); } function handleEqual() { if(isLocked)return; eqCount++; if(eqTimer)clearTimeout(eqTimer); eqTimer=setTimeout(()=>{eqCount=0;},EQ_TIMEOUT); if(eqCount>=EQ_SECRET){ eqCount=0; openSettings(); return; } if(!pendingOp)return; const cur=parseFloat(display), result=applyOp(accumulator,pendingOp,cur); topExpr=fmt(accumulator)+' '+pendingOp+' '+fmt(cur)+' ='; display=fmt(result); accumulator=result; pendingOp=null; waitNext=true; justEqual=true; render(); } function handleClear() { if(isLocked)return; display='0'; topExpr=''; accumulator=0; pendingOp=null; waitNext=false; justEqual=false; render(); } function handleBackspace() { if(isLocked)return; if(waitNext||justEqual)return; display=display.length { const now=new Date(), target=new Date(now.getTime()+offsetMinutes*60*1000); const m=target.getMonth()+1, d=String(target.getDate()).padStart(2,'0'); const h=String(target.getHours()).padStart(2,'0'), mi=String(target.getMinutes()).padStart(2,'0'); const magic=parseInt(String(m)+d+h+mi) - snapAcc; topExpr=fmt(snapAcc)+' +'; display=String(Math.abs(magic)); pendingOp='+'; waitNext=false; justEqual=false; render(); }); } function triggerMagicCustom() { if(!customTarget||isNaN(parseInt(customTarget))){ alert('請先在後台設定「模式二」的目標數字!'); return; } const snapAcc = accumulator; if(navigator.vibrate) navigator.vibrate([80, 60, 80]); lock(() => { const magic=parseInt(customTarget) - snapAcc; topExpr=fmt(snapAcc)+' +'; display=String(Math.abs(magic)); pendingOp='+'; waitNext=false; justEqual=false; render(); }); } // ══ 長按設定(dot=模式一,zero=模式二,兩者再次長按解鎖)══ function setupHold(el, onHold, onClick) { let held=false, timer=null; el.addEventListener('pointerdown', ()=>{ held=false; el.classList.add('holding'); timer=setTimeout(()=>{ held=true; el.classList.remove('holding'); if(!isLocked){ onHold(); } }, HOLD_MS); }); el.addEventListener('pointerup', ()=>{ clearTimeout(timer); el.classList.remove('holding'); if(!held)onClick(); }); el.addEventListener('pointerleave', ()=>{ clearTimeout(timer); el.classList.remove('holding'); }); el.addEventListener('contextmenu', e=>e.preventDefault()); } setupHold(elAdd, triggerMagicTime, ()=>handleOp('+')); setupHold(elZero, triggerMagicCustom, ()=>handleDigit('0')); // ══ 其他按鈕 ══ const bindings={ 'btn-1':()=>handleDigit('1'),'btn-2':()=>handleDigit('2'),'btn-3':()=>handleDigit('3'), 'btn-4':()=>handleDigit('4'),'btn-5':()=>handleDigit('5'),'btn-6':()=>handleDigit('6'), 'btn-7':()=>handleDigit('7'),'btn-8':()=>handleDigit('8'),'btn-9':()=>handleDigit('9'), 'btn-add':()=>handleOp('+'),'btn-sub':()=>handleOp('−'),'btn-mul':()=>handleOp('×'),'btn-div':()=>handleOp('÷'), 'btn-eq':handleEqual,'btn-c':handleClear,'btn-pm':handlePlusMinus, 'btn-pct':handlePercent,'btn-paren':()=>{},'backspace-btn':handleBackspace, }; Object.entries(bindings).forEach(([id,fn])=>{ const el=document.getElementById(id); if(el)el.addEventListener('click',fn); }); // ══ 設定 Modal ══ document.querySelectorAll('.tab-btn').forEach(btn=>{ btn.addEventListener('click',()=>{ document.querySelectorAll('.tab-btn').forEach(b=>b.classList.remove('active')); document.querySelectorAll('.tab-content').forEach(c=>c.classList.remove('active')); btn.classList.add('active'); document.getElementById(btn.dataset.tab).classList.add('active'); }); }); function updateTimePreview() { const m=parseInt(document.getElementById('offset-input').value)||0; const now=new Date(), target=new Date(now.getTime()+m*60*1000); const mo=target.getMonth()+1, d=String(target.getDate()).padStart(2,'0'); const h=String(target.getHours()).padStart(2,'0'), mi=String(target.getMinutes()).padStart(2,'0'); document.getElementById('preview-time').textContent=`${mo}${d}${h}${mi} → ${mo}/${d} ${h}:${mi}`; document.querySelectorAll('.quick-btn').forEach(b=>b.classList.toggle('active',parseInt(b.dataset.m)===m)); } function updateCustomPreview() { const v=document.getElementById('custom-input').value.trim(); document.getElementById('preview-custom').textContent=v||'—'; } document.getElementById('offset-input').addEventListener('input',updateTimePreview); document.getElementById('custom-input').addEventListener('input',updateCustomPreview); document.querySelectorAll('.quick-btn').forEach(b=>{ b.addEventListener('click',()=>{ document.getElementById('offset-input').value=b.dataset.m; updateTimePreview(); }); }); document.getElementById('save-time-btn').addEventListener('click',()=>{ const n=parseInt(document.getElementById('offset-input').value); const s=parseInt(document.getElementById('lock-input').value); if(isNaN(n)||n1440){alert('請輸入 0~1440 之間的數字');return;} if(isNaN(s)||s120){alert('鎖定秒數請輸入 5~120');return;} offsetMinutes=n; localStorage.setItem('magic_offset',n); lockSeconds=s; localStorage.setItem('magic_lock_seconds',s); const btn=document.getElementById('save-time-btn'); btn.textContent='✓ 已儲存!'; setTimeout(()=>{ btn.textContent='儲存模式一設定'; overlay.classList.remove('open'); },900); }); document.getElementById('save-custom-btn').addEventListener('click',()=>{ const v=document.getElementById('custom-input').value.trim(); if(!v||isNaN(parseInt(v))){alert('請輸入純數字');return;} customTarget=v; localStorage.setItem('magic_custom',v); const btn=document.getElementById('save-custom-btn'); btn.textContent='✓ 已儲存!'; setTimeout(()=>{ btn.textContent='儲存模式二設定'; overlay.classList.remove('open'); },900); }); document.getElementById('close-btn').addEventListener('click',()=>overlay.classList.remove('open')); overlay.addEventListener('click',e=>{ if(e.target===overlay)overlay.classList.remove('open'); }); function openSettings() { document.getElementById('offset-input').value=offsetMinutes; document.getElementById('lock-input').value=lockSeconds; document.getElementById('custom-input').value=customTarget; updateTimePreview(); updateCustomPreview(); overlay.classList.add('open'); } // ══ 加入主畫面圖示(canvas 畫計算機圖示)══ function generateIcon() { const c=document.createElement('canvas'); c.width=192; c.height=192; const ctx=c.getContext('2d'); // 背景 ctx.fillStyle='#f0f0f0'; ctx.roundRect(0,0,192,192,32); ctx.fill(); // 顯示列 ctx.fillStyle='#e0e0e0'; ctx.roundRect(16,16,160,48,8); ctx.fill(); ctx.fillStyle='#1a1a1a'; ctx.font='bold 28px sans-serif'; ctx.textAlign='right'; ctx.fillText('0',164,52); // 按鈕格 const cols=4, rows=5, bw=32, bh=22, gap=6, ox=16, oy=76; const colors=['#e0e0e0','#e0e0e0','#e0e0e0','#616161', '#fff','#fff','#fff','#616161', '#fff','#fff','#fff','#616161', '#fff','#fff','#fff','#616161', '#fff','#fff','#fff','#1db954']; for(let r=0;r<rows;r++) for(let col=0;col<cols;col++) { const i=r*cols+col; ctx.fillStyle=colors[i]; const x=ox+col*(bw+gap), y=oy+r*(bh+gap); ctx.beginPath(); ctx.roundRect(x,y,bw,bh,bw/2); ctx.fill(); } return c.toDataURL('image/png'); } // 加入 apple-touch-icon const iconLink=document.createElement('link'); iconLink.rel='apple-touch-icon'; iconLink.href=generateIcon(); document.head.appendChild(iconLink); render();