PromptBase
Upgrade
Close icon
General
Home
Marketplace
Create
Hire
Login
Chat
Sell
Explore

Prompt Details

Model
(gemini-3.1-pro)
Token size
571
Example input
[GAME_CONCEPT]: Stacking Jellies
Example output
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <title>舒缓果冻堆 - Healing Jelly</title> <style> :root { --bg-color: #f7f3e9; --text-color: #8e8d8a; --ui-bg: rgba(255, 255, 255, 0.6); } body, html { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; background-color: var(--bg-color); font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif; touch-action: none; } canvas { display: block; } #ui { position: absolute; top: 20px; left: 0; right: 0; text-align: center; pointer-events: none; color: var(--text-color); user-select: none; z-index: 10; } h1 { font-weight: 300; font-size: 1.5rem; letter-spacing: 2px; margin-bottom: 5px; opacity: 0.8; } p { font-size: 0.9rem; opacity: 0.6; } #hint { position: absolute; bottom: 30px; left: 0; right: 0; text-align: center; color: var(--text-color); opacity: 0.4; font-size: 0.8rem; pointer-events: none; } </style> </head> <body> <div id="ui"> <h1>舒缓果冻堆</h1> <p>呼吸,叠放,放松</p> </div> <div id="hint">轻点屏幕 放置果冻</div> <canvas id="gameCanvas"></canvas> <script> /** * SoundManager - Web Audio API 五声音阶 */ class SoundManager { constructor() { this.ctx = null; this.pentatonic = [261.63, 293.66, 329.63, 392.00, 440.00, 523.25]; this.lastNote = -1; } init() { if (!this.ctx) { this.ctx = new (window.AudioContext || window.webkitAudioContext)(); } } playJellySound() { this.init(); if (this.ctx.state === 'suspended') this.ctx.resume(); const osc = this.ctx.createOscillator(); const gain = this.ctx.createGain(); let noteIdx; do { noteIdx = Math.floor(Math.random() * this.pentatonic.length); } while (noteIdx === this.lastNote); this.lastNote = noteIdx; osc.type = 'sine'; osc.frequency.setValueAtTime(this.pentatonic[noteIdx], this.ctx.currentTime); gain.gain.setValueAtTime(0, this.ctx.currentTime); gain.gain.linearRampToValueAtTime(0.12, this.ctx.currentTime + 0.05); gain.gain.exponentialRampToValueAtTime(0.001, this.ctx.currentTime + 1.2); osc.connect(gain); gain.connect(this.ctx.destination); osc.start(); osc.stop(this.ctx.currentTime + 1.2); } playRippleSound() { this.init(); if (this.ctx.state === 'suspended') this.ctx.resume(); const osc = this.ctx.createOscillator(); const gain = this.ctx.createGain(); osc.type = 'sine'; osc.frequency.setValueAtTime(600, this.ctx.currentTime); osc.frequency.exponentialRampToValueAtTime(300, this.ctx.currentTime + 0.3); gain.gain.setValueAtTime(0.04, this.ctx.currentTime); gain.gain.exponentialRampToValueAtTime(0.001, this.ctx.currentTime + 0.3); osc.connect(gain); gain.connect(this.ctx.destination); osc.start(); osc.stop(this.ctx.currentTime + 0.3); } } const sounds = new SoundManager(); const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); let width, height; let jellies = []; let particles = []; let ripples = []; let cameraY = 0; let smoothedHighestY = 0; const PALETTE = ['#FFB7B2', '#FFDAC1', '#E2F0CB', '#B5EAD7', '#C7CEEA', '#FDFD96']; const GRAVITY = 0.3; class Jelly { constructor(x, y, w, h, color) { this.x = x; this.y = y; this.w = w; this.h = h; this.color = color; this.vy = 0; this.isStatic = false; this.wobble = 0; this.wobbleSpeed = 0; } update(ground) { if (this.isStatic) { this.y += (ground - this.h / 2 - this.y) * 0.2; this.wobbleSpeed *= 0.85; this.wobble += this.wobbleSpeed; this.wobble *= 0.8; return; } this.vy += GRAVITY; this.y += this.vy; if (this.y + this.h / 2 >= ground) { const impactVel = this.vy; this.y = ground - this.h / 2; if (Math.abs(this.vy) < 1.2) { this.isStatic = true; this.vy = 0; this.triggerWobble(10); sounds.playJellySound(); createImpactParticles(this.x, this.y + this.h / 2, this.color); } else { this.vy *= -0.3; this.triggerWobble(impactVel * 2); } } } triggerWobble(force) { this.wobbleSpeed = force; } draw() { ctx.save(); ctx.translate(this.x, this.y - cameraY); const wMod = Math.sin(Date.now() * 0.01) * this.wobble * 0.2; const hMod = this.wobble * 0.35; const drawW = this.w + wMod; const drawH = this.h - hMod; ctx.shadowBlur = 20; ctx.shadowColor = 'rgba(0,0,0,0.03)'; ctx.fillStyle = this.color; ctx.beginPath(); ctx.roundRect(-drawW / 2, -drawH / 2, drawW, drawH, 15); ctx.fill(); ctx.fillStyle = 'rgba(255,255,255,0.25)'; ctx.beginPath(); ctx.roundRect(-drawW / 2 + 10, -drawH / 2 + 6, drawW - 20, 8, 4); ctx.fill(); ctx.restore(); } } class Particle { constructor(x, y, color) { this.x = x; this.y = y; this.vx = (Math.random() - 0.5) * 4; this.vy = (Math.random() - 1) * 4; this.size = Math.random() * 6 + 2; this.color = color; this.life = 1.0; } update() { this.x += this.vx; this.y += this.vy; this.vy += 0.1; this.life -= 0.015; } draw() { ctx.globalAlpha = this.life; ctx.fillStyle = this.color; ctx.beginPath(); ctx.arc(this.x, this.y - cameraY, this.size, 0, Math.PI * 2); ctx.fill(); ctx.globalAlpha = 1; } } class Ripple { constructor(x, y) { this.x = x; this.y = y; this.r = 0; this.life = 1.0; } update() { this.r += 3; this.life -= 0.02; } draw() { ctx.strokeStyle = `rgba(142, 141, 138, ${this.life * 0.2})`; ctx.lineWidth = 2; ctx.beginPath(); ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2); ctx.stroke(); } } function resize() { width = window.innerWidth; height = window.innerHeight; canvas.width = width; canvas.height = height; // 初始化平滑高度,确保一开始 finalCameraTarget 为 0 if (smoothedHighestY === 0 || smoothedHighestY > height) { smoothedHighestY = height; } } function createImpactParticles(x, y, color) { for (let i = 0; i < 6; i++) particles.push(new Particle(x, y, color)); } function spawnJelly(x, y) { const w = Math.random() * 40 + 90; const h = 45; const color = PALETTE[Math.floor(Math.random() * PALETTE.length)]; // 修正生成逻辑,防止第一下点击位置过低导致生成的果冻已经在屏幕外 const spawnBaseY = Math.min(y, cameraY + height * 0.5); jellies.push(new Jelly(x, spawnBaseY - 200, w, h, color)); } function init() { resize(); window.addEventListener('resize', resize); const handleInput = (e) => { const rect = canvas.getBoundingClientRect(); const clientX = e.clientX || (e.touches && e.touches[0].clientX); const clientY = e.clientY || (e.touches && e.touches[0].clientY); if (clientX !== undefined) { const x = clientX - rect.left; const y = clientY - rect.top; ripples.push(new Ripple(x, y)); sounds.playRippleSound(); spawnJelly(x, y + cameraY); } }; canvas.addEventListener('mousedown', handleInput); canvas.addEventListener('touchstart', (e) => { e.preventDefault(); handleInput(e); }, { passive: false }); loop(); } function loop() { const grad = ctx.createLinearGradient(0, 0, 0, height); grad.addColorStop(0, '#fdfcf0'); grad.addColorStop(1, '#f7f3e9'); ctx.fillStyle = grad; ctx.fillRect(0, 0, width, height); // --- 修复后的摄像机逻辑 --- // 默认最高点是屏幕底部,只有出现果冻后才更新 let actualTopY = height; let hasStableJelly = false; jellies.forEach(j => { if (j.isStatic || Math.abs(j.vy) < 2) { if (j.y < actualTopY) { actualTopY = j.y; hasStableJelly = true; } } }); // 如果还没有稳定的果冻,保持 smoothedHighestY 在底部 let targetForSmoothed = hasStableJelly ? actualTopY : height; smoothedHighestY += (targetForSmoothed - smoothedHighestY) * 0.08; // 目标是将最高点保持在屏幕 60% 的高度 // 修正:只有当 smoothedHighestY 真的很高(数值小)时,finalCameraTarget 才可能为负数(向上卷动) let finalCameraTarget = Math.min(0, smoothedHighestY - height * 0.6); let diff = finalCameraTarget - cameraY; let followSpeed = diff < 0 ? 0.05 : 0.01; cameraY += diff * followSpeed; // 绘制装饰元素 for (let i = ripples.length - 1; i >= 0; i--) { ripples[i].update(); ripples[i].draw(); if (ripples[i].life <= 0) ripples.splice(i, 1); } for (let i = particles.length - 1; i >= 0; i--) { particles[i].update(); particles[i].draw(); if (particles[i].life <= 0) particles.splice(i, 1); } // 更新果冻 jellies.forEach((j, index) => { let currentGround = height - 40; for (let k = 0; k < jellies.length; k++) { const other = jellies[k]; if (k !== index && other.y > j.y) { const horizontalOverlap = Math.abs(j.x - other.x) < (j.w / 2 + other.w / 2) - 10; if (horizontalOverlap) { const surfaceY = other.y - other.h / 2; if (surfaceY < currentGround) currentGround = surfaceY; } } } j.update(currentGround); j.draw(); }); // 保持性能 if (jellies.length > 60 && jellies[0].y > height + cameraY + 600) { jellies.shift(); } requestAnimationFrame(loop); } window.onload = init; </script> </body> </html>
♊️ Gemini

ASMR Web Game Generator

Add to Cart
Instant accessInstant access
Usage rightsCommercial use
Money-back guaranteeMoney‑back
By purchasing this prompt, you agree to our terms of service
GEMINI-3.1-PRO
Tested icon
Guide icon
4 examples icon
Free credits icon
Generates self-contained, single-file HTML5 healing mini-games. Just input a simple concept (e.g., "Stacking Jellies"), and it creates a fully playable game with zero external assets. Features include a built-in Web Audio API synthesizer for relaxing ASMR sounds, soft Morandi color palettes, and low-gravity physics for a satisfying "flow" state. Perfect for creating instant stress-relief web games that are responsive on both mobile and desktop!
...more
Added over 1 month ago
Report
Browse Marketplace