⬅ ギャラリーに戻る
✏️ '
timer3.html
' を修正中... (終わったら保存を押してね)
📷 素材アップロード
アップロード
🛠️ プログラム作成
[修正モード]
ファイル名:
.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>進化版!わんわんタイマー</title> <link href="https://fonts.googleapis.com/css2?family=M+PLUS+Rounded+1c:wght@400;800&display=swap" rel="stylesheet"> <style> :root { --primary-color: #FFB347; --secondary-color: #F57C00; --bg-color: #FFF9F0; --bowl-color: #8D6E63; --text-color: #5D4037; } body { font-family: 'M PLUS Rounded 1c', sans-serif; background-color: var(--bg-color); color: var(--text-color); display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; margin: 0; user-select: none; } h1 { font-size: 1.6rem; margin: 10px 0; } /* ステージ */ .stage-container { background: white; padding: 20px 30px 30px; border-radius: 30px; box-shadow: 0 10px 25px rgba(0,0,0,0.1); display: flex; flex-direction: column; align-items: center; margin-bottom: 20px; } .stage { position: relative; width: 300px; height: 280px; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; } /* キャラクター */ .character { font-size: 100px; cursor: pointer; transition: transform 0.3s; filter: drop-shadow(0 4px 4px rgba(0,0,0,0.15)); z-index: 10; } .character:active { transform: scale(0.9); } .character.eating { animation: munch 0.25s infinite alternate; } .character.happy { animation: happyJump 0.6s infinite alternate; } @keyframes munch { 0% { transform: translateY(0); } 100% { transform: translateY(5px) rotate(-2deg); } } @keyframes happyJump { 0% { transform: translateY(0); } 100% { transform: translateY(-20px) rotate(5deg); } } /* お皿とエサ */ .bowl-container { width: 240px; display: flex; flex-direction: column; align-items: center; } .food-items-grid { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px; width: 90%; margin-bottom: 5px; min-height: 30px; } .food-item { font-size: 24px; transition: all 0.5s; } .food-item.eaten { opacity: 0; transform: scale(0.5) translateY(-20px); } .food-item.current { animation: shake 0.5s infinite; filter: brightness(1.2); } @keyframes shake { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(2px); } } .bowl { width: 220px; height: 45px; background-color: var(--bowl-color); border-radius: 15px 15px 50px 50px; box-shadow: inset 0 -5px 10px rgba(0,0,0,0.2); } /* 吹き出し */ .message-box { position: absolute; top: 0; background: white; padding: 10px 20px; border-radius: 20px; box-shadow: 0 4px 10px rgba(0,0,0,0.1); font-weight: bold; opacity: 0; transform: translateY(10px); transition: 0.3s; } .message-box.show { opacity: 1; transform: translateY(0); } /* タイマー文字 */ .timer-display { font-size: 4rem; font-weight: 800; color: var(--primary-color); margin: 10px 0; font-feature-settings: "tnum"; text-shadow: 2px 2px 0px #FFF; } /* 操作パネル */ .settings-wrapper { background: #FFF3E0; padding: 15px; border-radius: 20px; margin-bottom: 20px; transition: 0.3s; } .settings-wrapper.hidden { opacity: 0; visibility: hidden; height: 0; padding: 0; margin: 0; } input, select { padding: 8px; border: 2px solid var(--primary-color); border-radius: 8px; font-size: 1rem; text-align: center; } button { padding: 12px 30px; border: none; border-radius: 50px; font-size: 1.2rem; font-weight: bold; cursor: pointer; color: white; box-shadow: 0 4px 0 rgba(0,0,0,0.2); transition: 0.1s; } button:active { transform: translateY(2px); box-shadow: 0 2px 0 rgba(0,0,0,0.2); } .btn-start { background-color: var(--primary-color); } .btn-reset { background-color: #90A4AE; font-size: 1rem; padding: 10px 20px; } .controls { display: flex; gap: 15px; align-items: center; } </style> </head> <body> <h1>わんわんタイマー 🐾</h1> <div class="stage-container"> <div class="stage"> <div class="message-box" id="messageBox">準備OKだワン!</div> <div class="character" id="character" onclick="playStart()">🐕</div> <div class="bowl-container"> <div class="food-items-grid" id="foodGrid"></div> <div class="bowl"></div> </div> </div> <div class="timer-display" id="timerDisplay">25:00</div> </div> <div class="settings-wrapper" id="settingsWrapper"> <div style="margin-bottom: 10px;"> <label>犬種:</label> <select id="breedSelect"> <option value="🐕">柴犬</option> <option value="🐩">プードル</option> <option value="🐶">チワワ</option> <option value="🦮">レトリバー</option> </select> </div> <div> <input type="number" id="inputMin" value="25" min="0" style="width:60px;"> 分 <input type="number" id="inputSec" value="00" min="0" max="59" style="width:60px;"> 秒 </div> </div> <div class="controls"> <button class="btn-start" id="startBtn" onclick="toggleTimer()">スタート</button> <button class="btn-reset" onclick="resetTimer()">リセット</button> </div> <script> // ▼▼▼ ここが重要!音声ファイルの設定 ▼▼▼ // アップロードしたファイル名と完全に一致させてね(.wav も忘れずに) const soundStart = new Audio('media/startwav.wav'); // 画面にあったファイル名 const soundFinish = new Audio('media/finish.wav'); // ※これもアップロードしてね! // 音量 (0.0 〜 1.0) soundStart.volume = 0.8; soundFinish.volume = 1.0; // 便利関数 function playStart() { soundStart.currentTime = 0; soundStart.play().catch(e => console.log("再生エラー: 画面をクリックしてから試してね")); } function playFinish() { soundFinish.currentTime = 0; soundFinish.play().catch(e => console.log("再生エラー: finish.wavがないかも?")); } // --- 以下ロジック --- let timerInterval, totalSeconds = 0, remainingSeconds = 0, isRunning = false; const els = { char: document.getElementById('character'), msg: document.getElementById('messageBox'), time: document.getElementById('timerDisplay'), grid: document.getElementById('foodGrid'), btn: document.getElementById('startBtn'), set: document.getElementById('settingsWrapper'), min: document.getElementById('inputMin'), sec: document.getElementById('inputSec'), breed: document.getElementById('breedSelect') }; // 初期表示 updateTimeDisplay(parseInt(els.min.value) * 60); // イベント els.breed.addEventListener('change', () => { els.char.textContent = els.breed.value; playStart(); }); [els.min, els.sec].forEach(el => el.addEventListener('change', () => { updateTimeDisplay(getInputValue()); })); function getInputValue() { return (parseInt(els.min.value)||0) * 60 + (parseInt(els.sec.value)||0); } function toggleTimer() { isRunning ? pause() : start(); } function start() { if (!timerInterval && remainingSeconds === 0) { totalSeconds = remainingSeconds = getInputValue(); if (totalSeconds <= 0) return; setupFood(totalSeconds); els.set.classList.add('hidden'); } if (remainingSeconds > 0) { isRunning = true; els.btn.textContent = "一時停止"; els.btn.style.backgroundColor = "#FF8A65"; els.char.classList.add('eating'); showMessage("ガツガツ!"); playStart(); // スタート音再生 timerInterval = setInterval(() => { remainingSeconds--; updateTimeDisplay(remainingSeconds); updateFood(); if (remainingSeconds <= 0) finish(); }, 1000); } } function pause() { isRunning = false; clearInterval(timerInterval); els.btn.textContent = "再開"; els.btn.style.backgroundColor = ""; els.char.classList.remove('eating'); showMessage("待て!"); } function resetTimer() { pause(); els.btn.textContent = "スタート"; els.set.classList.remove('hidden'); totalSeconds = remainingSeconds = 0; timerInterval = null; els.grid.innerHTML = ''; els.char.classList.remove('happy'); updateTimeDisplay(getInputValue()); showMessage("準備OKだワン!"); } function finish() { pause(); els.btn.textContent = "完了!"; els.char.classList.add('happy'); showMessage("ごちそうさま!✨"); updateTimeDisplay(0); updateFood(); // 全部消す playFinish(); // 完了音再生 } function updateTimeDisplay(sec) { const m = Math.floor(sec / 60); const s = sec % 60; els.time.textContent = `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`; } function showMessage(txt) { els.msg.textContent = txt; els.msg.classList.add('show'); } function setupFood(sec) { els.grid.innerHTML = ''; // 2分に1個、最大15個 let count = Math.min(15, Math.max(3, Math.floor(sec / 120))); for(let i=0; i<count; i++) { const d = document.createElement('div'); d.className = 'food-item'; d.textContent = '🍖'; els.grid.appendChild(d); } } function updateFood() { if (totalSeconds <= 0) return; const items = els.grid.children; const progress = remainingSeconds / totalSeconds; const remainCount = Math.ceil(progress * items.length); for (let i = 0; i < items.length; i++) { if (i >= remainCount) { items[i].classList.add('eaten'); items[i].classList.remove('current'); } else if (i === remainCount - 1 && isRunning) { items[i].classList.add('current'); } else { items[i].classList.remove('eaten', 'current'); } } } </script> </body> </html>
上書き保存する
キャンセルして新規作成に戻る
📂 APP の作品
ProVocab - 縦スクロール暗記版
eigo2.html (01/15 10:37)
✏️ 修正
🌏 公開
🗑️
ProVocab - 語源マスター版
eigo.html (01/15 10:37)
✏️ 修正
🌏 公開
🗑️
進化版!わんわんタイマー
timer3.html (01/14 13:38)
✏️ 修正
🌏 公開
🗑️
わんわん応援タイマー
timer.html (01/14 12:49)
✏️ 修正
🌏 公開
🗑️
進化版!わんわんタイマー
timer2.html (01/14 12:17)
✏️ 修正
🌏 公開
🗑️