From 42adcdaa8797b0421bb72fe3c19cb31b9077b081 Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Wed, 19 Aug 2026 13:26:07 +0000 Subject: [PATCH] Session 1: Particle effects system with click, building, and achievement visual feedback --- css/game.css | 26 +++++++ dev-journal.md | 26 +++++++ index.html | 1 + js/achievements.js | 8 ++ js/game.js | 9 +++ js/main.js | 3 + js/particles.js | 184 +++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 257 insertions(+) create mode 100644 js/particles.js diff --git a/css/game.css b/css/game.css index d6b4681..2febed7 100644 --- a/css/game.css +++ b/css/game.css @@ -556,6 +556,32 @@ h2, h3 { } } +/* Particle Effects */ +.particle { + will-change: transform, opacity; +} + +/* Ambient Stars Background */ +.ambient-star { + position: absolute; + background: radial-gradient(circle, #ffffff 0%, transparent 70%); + border-radius: 50%; + animation: twinkle ease-in-out infinite; + pointer-events: none; + z-index: 1; +} + +@keyframes twinkle { + 0%, 100% { + opacity: 0.2; + transform: scale(1); + } + 50% { + opacity: 0.8; + transform: scale(1.3); + } +} + /* Scrollbar Styling */ ::-webkit-scrollbar { width: 8px; diff --git a/dev-journal.md b/dev-journal.md index c8d58de..8128e87 100644 --- a/dev-journal.md +++ b/dev-journal.md @@ -29,3 +29,29 @@ The stats panel tracks and displays: - Visual effects (particle effects on click) - Mobile touch optimizations - Prestige/reset system + +--- + +### Session 1 - 2026-08-19 (14:35 UTC) +**Status:** ✅ Particle Effects System Added + +#### What was done: +- Created a complete particle effects system for visual feedback +- Added click sparkle particles when harvesting stardust +- Added building purchase burst effects on the building card +- Added achievement unlock celebration effects +- Added ambient twinkling stars to the background +- Integrated particles into game.js, achievements.js, and main.js + +#### Files modified: +- `js/particles.js` - New file with Particle system (click, building, achievement effects + ambient stars) +- `js/game.js` - Added particle calls on harvest and buyBuilding +- `js/achievements.js` - Added particle effect on achievement unlock +- `js/main.js` - Added ambient star creation on init +- `css/game.css` - Added particle styles and twinkle animation +- `index.html` - Added particles.js script tag + +#### Next goals: +- Mobile touch optimizations (tap feedback, responsive layout) +- Prestige/reset system with bonuses +- Sound effects for clicks and purchases diff --git a/index.html b/index.html index ebd52ec..6f6d7aa 100644 --- a/index.html +++ b/index.html @@ -102,6 +102,7 @@ + diff --git a/js/achievements.js b/js/achievements.js index dcc5f42..8fad98d 100644 --- a/js/achievements.js +++ b/js/achievements.js @@ -164,6 +164,14 @@ const Achievements = { if (achievement.condition(Game.state)) { Game.state.achievements.push(id); UI.showNotification(`Achievement: ${achievement.name}!`, 'achievement'); + + // Particle effect for achievement unlock + const countEl = document.querySelector('#achievements-tab h3'); + if (countEl) { + const rect = countEl.getBoundingClientRect(); + Particles.createAchievementEffect(rect.left + rect.width / 2, rect.top + rect.height / 2); + } + console.log(`🏆 Achievement unlocked: ${achievement.name}`); } } diff --git a/js/game.js b/js/game.js index c19e11e..d9fc4f5 100644 --- a/js/game.js +++ b/js/game.js @@ -101,6 +101,7 @@ const Game = { // Visual feedback UI.showFloatingText(event.clientX, event.clientY, `+${this.formatNumber(amount)}`); + Particles.createClickParticles(event.clientX, event.clientY, 8); UI.update(); }, @@ -180,6 +181,14 @@ const Game = { this.state.buildings[buildingId] = (this.state.buildings[buildingId] || 0) + 1; UI.showNotification(`Bought ${BUILDINGS[buildingId].name}!`, 'success'); + + // Particle effect on building purchase + const card = document.getElementById(`building-${buildingId}`); + if (card) { + const rect = card.getBoundingClientRect(); + Particles.createBuildingEffect(rect.left + rect.width / 2, rect.top + rect.height / 2); + } + UI.update(); return true; } diff --git a/js/main.js b/js/main.js index b98535e..0af88cd 100644 --- a/js/main.js +++ b/js/main.js @@ -5,6 +5,9 @@ document.addEventListener('DOMContentLoaded', () => { Game.init(); + // Create ambient background stars + Particles.createAmbientStars(15); + // Show last save time const lastSave = SaveSystem.getLastSaveTime(); if (lastSave) { diff --git a/js/particles.js b/js/particles.js new file mode 100644 index 0000000..a46a68a --- /dev/null +++ b/js/particles.js @@ -0,0 +1,184 @@ +/** + * Cosmic Garden - Particle System + * Creates visual particle effects for clicks and achievements + */ + +const Particles = { + /** + * Create sparkle particles on click + */ + createClickParticles(x, y, count = 8) { + const colors = ['#ffd700', '#9b59b6', '#3498db', '#2ecc71', '#ffffff']; + + for (let i = 0; i < count; i++) { + const particle = document.createElement('div'); + particle.className = 'particle'; + + // Random properties + const angle = (Math.PI * 2 * i) / count + (Math.random() - 0.5); + const velocity = 50 + Math.random() * 50; + const size = 6 + Math.random() * 8; + const color = colors[Math.floor(Math.random() * colors.length)]; + + particle.style.cssText = ` + left: ${x}px; + top: ${y}px; + width: ${size}px; + height: ${size}px; + background: ${color}; + border-radius: 50%; + pointer-events: none; + position: fixed; + z-index: 998; + `; + + document.body.appendChild(particle); + + // Animate + const animation = particle.animate([ + { + transform: 'translate(-50%, -50%) scale(1)', + opacity: 1 + }, + { + transform: `translate(calc(-50% + ${Math.cos(angle) * velocity}px), calc(-50% + ${Math.sin(angle) * velocity}px)) scale(0)`, + opacity: 0 + } + ], { + duration: 600 + Math.random() * 200, + easing: 'cubic-bezier(0, 0.9, 0.57, 1)' + }); + + animation.onfinish = () => particle.remove(); + } + }, + + /** + * Create achievement unlock effect + */ + createAchievementEffect(x, y) { + const colors = ['#ffd700', '#ff6b6b', '#4ecdc4', '#45b7d1', '#96ceb4']; + + // Burst of particles + for (let i = 0; i < 20; i++) { + const particle = document.createElement('div'); + particle.className = 'particle achievement-particle'; + + const angle = (Math.PI * 2 * i) / 20; + const velocity = 80 + Math.random() * 60; + const size = 8 + Math.random() * 12; + const color = colors[Math.floor(Math.random() * colors.length)]; + + particle.style.cssText = ` + left: ${x}px; + top: ${y}px; + width: ${size}px; + height: ${size}px; + background: ${color}; + border-radius: 50%; + pointer-events: none; + position: fixed; + z-index: 998; + box-shadow: 0 0 10px ${color}; + `; + + document.body.appendChild(particle); + + const animation = particle.animate([ + { + transform: 'translate(-50%, -50%) scale(1)', + opacity: 1 + }, + { + transform: `translate(calc(-50% + ${Math.cos(angle) * velocity}px), calc(-50% + ${Math.sin(angle) * velocity}px)) scale(0.5)`, + opacity: 0.8 + }, + { + transform: `translate(calc(-50% + ${Math.cos(angle) * velocity * 1.5}px), calc(-50% + ${Math.sin(angle) * velocity * 1.5}px)) scale(0)`, + opacity: 0 + } + ], { + duration: 1000, + easing: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)' + }); + + animation.onfinish = () => particle.remove(); + } + }, + + /** + * Create building purchase effect + */ + createBuildingEffect(x, y) { + const colors = ['#2ecc71', '#27ae60', '#1abc9c']; + + for (let i = 0; i < 12; i++) { + const particle = document.createElement('div'); + particle.className = 'particle building-particle'; + + const angle = (Math.PI * 2 * i) / 12; + const velocity = 60 + Math.random() * 40; + const size = 5 + Math.random() * 6; + const color = colors[Math.floor(Math.random() * colors.length)]; + + particle.style.cssText = ` + left: ${x}px; + top: ${y}px; + width: ${size}px; + height: ${size}px; + background: ${color}; + border-radius: 2px; + pointer-events: none; + position: fixed; + z-index: 998; + `; + + document.body.appendChild(particle); + + const animation = particle.animate([ + { + transform: 'translate(-50%, -50%) rotate(0deg) scale(1)', + opacity: 1 + }, + { + transform: `translate(calc(-50% + ${Math.cos(angle) * velocity}px), calc(-50% + ${Math.sin(angle) * velocity}px)) rotate(${360 + Math.random() * 180}deg) scale(0)`, + opacity: 0 + } + ], { + duration: 700, + easing: 'ease-out' + }); + + animation.onfinish = () => particle.remove(); + } + }, + + /** + * Create ambient floating stars in the background + */ + createAmbientStars(count = 15) { + for (let i = 0; i < count; i++) { + const star = document.createElement('div'); + star.className = 'ambient-star'; + + const size = 2 + Math.random() * 3; + const left = Math.random() * 100; + const delay = Math.random() * 5; + const duration = 3 + Math.random() * 2; + + star.style.cssText = ` + width: ${size}px; + height: ${size}px; + left: ${left}%; + top: ${Math.random() * 100}%; + animation-delay: ${delay}s; + animation-duration: ${duration}s; + `; + + document.getElementById('game-container').appendChild(star); + } + } +}; + +// Make globally accessible +window.Particles = Particles;