🎈🎉✨💡🐱🏍🐱👓🐱🏍🎨🖍️📝
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>文字練習アプリ ✏️🎉</title>
<style>
@keyframes bounce {
0%, 20%, 50%, 80%, 100% { transform: translateY(0); }
40% { transform: translateY(-20px); }
60% { transform: translateY(-10px); }
}
@keyframes sparkle {
0% { opacity: 0; }
50% { opacity: 1; }
100% { opacity: 0; }
}
.animate-bounce {
animation: bounce 1s;
}
.animate-sparkle {
position: absolute;
width: 10px;
height: 10px;
background: yellow;
border-radius: 50%;
animation: sparkle 1s infinite;
}
</style>
</head>
<body>
<div style="width: 400px; height: 400px; border: 2px solid #ccc; border-radius: 10px; position: relative; overflow: hidden; background-color: #f0f8ff;">
<div id="emoji-container" style="position: absolute; top: 10px; right: 10px;">
🎈🎉✨💡🐱🏍🐱👓🐱🏍🎨🖍️📝
</div>
<div style="text-align: center; padding: 10px;">
<button id="start-btn" style="font-size: 16px; padding: 10px 20px; cursor: pointer;">🎤 音声入力開始</button>
<input type="text" id="text-input" maxlength="20" style="display: none; font-size: 16px; padding: 5px; margin-top: 10px;">
<div id="characters" style="margin-top: 20px; display: flex; flex-wrap: wrap; justify-content: center;">
<!-- 大きなひらがなとキャンバスがここに表示されます -->
</div>
</div>
<div id="sparkle-container"></div>
</div>
<script>
const startBtn = document.getElementById('start-btn');
const textInput = document.getElementById('text-input');
const charactersDiv = document.getElementById('characters');
const sparkleContainer = document.getElementById('sparkle-container');
// 音声認識の設定
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
const recognition = new SpeechRecognition();
recognition.lang = 'ja-JP';
recognition.maxAlternatives = 1;
startBtn.addEventListener('click', () => {
startBtn.classList.add('animate-bounce');
recognition.start();
});
recognition.onresult = (event) => {
const transcript = event.results[0][0].transcript;
const hiragana = toHiragana(transcript).substring(0,20);
displayCharacters(hiragana);
startBtn.classList.remove('animate-bounce');
};
recognition.onerror = () => {
startBtn.classList.remove('animate-bounce');
alert('音声認識に失敗しました。');
};
function toHiragana(str) {
return str.replace(/[\u30A1-\u30F6]/g, function(match) {
const chr = match.charCodeAt(0) - 0x60;
return String.fromCharCode(chr);
});
}
function displayCharacters(text) {
charactersDiv.innerHTML = '';
for(let char of text){
const charDiv = document.createElement('div');
charDiv.style.margin = '10px';
charDiv.style.textAlign = 'center';
charDiv.innerHTML = `<div style="font-size: 36px;">${char}</div>
<canvas width="50" height="50" style="border: 1px solid #000; touch-action: none;"></canvas>`;
charactersDiv.appendChild(charDiv);
addCanvasEvents(char);
}
}
function addCanvasEvents(char) {
const canvases = document.querySelectorAll('canvas');
const canvas = canvases[canvases.length -1];
const ctx = canvas.getContext('2d');
let drawing = false;
canvas.addEventListener('mousedown', startDraw);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', endDraw);
canvas.addEventListener('touchstart', startDrawTouch, {passive: false});
canvas.addEventListener('touchmove', drawTouch, {passive: false});
canvas.addEventListener('touchend', endDraw, {passive: false});
function startDraw(e) {
drawing = true;
ctx.beginPath();
ctx.moveTo(e.offsetX, e.offsetY);
}
function draw(e) {
if(!drawing) return;
ctx.lineTo(e.offsetX, e.offsetY);
ctx.stroke();
}
function endDraw() {
drawing = false;
// クリック時にキラキラアニメーション
createSparkle(e.clientX, e.clientY);
}
function startDrawTouch(e) {
e.preventDefault();
const rect = canvas.getBoundingClientRect();
const touch = e.touches[0];
const x = touch.clientX - rect.left;
const y = touch.clientY - rect.top;
drawing = true;
ctx.beginPath();
ctx.moveTo(x, y);
}
function drawTouch(e) {
e.preventDefault();
if(!drawing) return;
const rect = canvas.getBoundingClientRect();
const touch = e.touches[0];
const x = touch.clientX - rect.left;
const y = touch.clientY - rect.top;
ctx.lineTo(x, y);
ctx.stroke();
}
}
function createSparkle(x, y) {
const sparkle = document.createElement('div');
sparkle.classList.add('animate-sparkle');
sparkle.style.left = x + 'px';
sparkle.style.top = y + 'px';
sparkleContainer.appendChild(sparkle);
setTimeout(() => {
sparkle.remove();
}, 1000);
}
</script>
</body>
</html>
```