LukasBe commited on
Commit
793742e
Β·
verified Β·
1 Parent(s): 2909495

Add 2 files

Browse files
Files changed (2) hide show
  1. index.html +453 -27
  2. prompts.txt +2 -1
index.html CHANGED
@@ -46,6 +46,7 @@
46
  #gameArea {
47
  touch-action: manipulation;
48
  background: radial-gradient(circle at center, #1a202c 0%, #111827 100%);
 
49
  }
50
 
51
  .kitchen-counter {
@@ -76,30 +77,181 @@
76
  50% { box-shadow: 0 0 30px 15px rgba(255, 255, 255, 0.7); }
77
  100% { box-shadow: 0 0 0 0 rgba(255, 255, 255, 0); }
78
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  </style>
80
  </head>
81
  <body class="bg-gray-900 text-white font-sans overflow-hidden">
82
  <!-- Start Screen -->
83
  <div id="startScreen" class="fixed inset-0 flex flex-col items-center justify-center bg-gradient-to-br from-gray-900 to-gray-800 z-10 transition-opacity duration-500">
84
- <div class="text-center mb-12">
 
 
 
 
 
 
 
 
85
  <h1 class="text-7xl font-bold mb-4 text-yellow-400 glow">🍳 RHYTHM CHEF</h1>
86
  <h2 class="text-4xl mb-6 text-yellow-300 glow">Beat Bites Deluxe</h2>
87
  <div class="text-xl text-gray-300 max-w-md mx-auto">
88
  Tap the ingredients in rhythm to cook up perfect dishes!
89
  </div>
90
  </div>
91
- <button id="startButton" class="bg-gradient-to-r from-yellow-500 to-yellow-600 hover:from-yellow-400 hover:to-yellow-500 text-4xl text-gray-900 font-bold py-5 px-16 rounded-full transition-all transform hover:scale-105 shadow-lg glow">
92
  START COOKING
93
  </button>
94
- <div class="absolute bottom-8 text-gray-400 text-sm">
95
  Tap the beat when ingredients reach the counter
96
  </div>
97
  </div>
98
 
99
  <!-- Game Screen -->
100
  <div id="gameScreen" class="fixed inset-0 hidden flex flex-col">
 
 
 
101
  <!-- Score Display -->
102
- <div class="flex justify-between px-8 pt-6">
103
  <div class="text-4xl font-bold score-glow">
104
  πŸ† <span id="score">0</span>
105
  </div>
@@ -113,6 +265,9 @@
113
  <!-- Floating particles background -->
114
  <div id="particles"></div>
115
 
 
 
 
116
  <!-- Target Zone (Kitchen Counter) -->
117
  <div id="targetZone" class="kitchen-counter absolute left-0 right-0 h-24 rounded-t-3xl flex items-center justify-center" style="bottom: 20%;">
118
  <div class="w-full h-1 bg-yellow-300 bg-opacity-50 rounded-full mx-8"></div>
@@ -120,12 +275,18 @@
120
 
121
  <!-- Feedback Text -->
122
  <div id="feedbackText" class="absolute left-1/2 transform -translate-x-1/2 text-6xl font-bold text-center opacity-0" style="bottom: 30%;"></div>
 
 
 
 
 
 
123
  </div>
124
  </div>
125
 
126
  <!-- End Screen -->
127
  <div id="endScreen" class="fixed inset-0 hidden flex flex-col items-center justify-center bg-gray-900 bg-opacity-95 z-20">
128
- <div class="text-center">
129
  <h2 class="text-6xl font-bold mb-8 text-yellow-400 glow">DISH COMPLETE! πŸŽ‰</h2>
130
  <div class="text-5xl mb-8">Final Score: <span id="finalScore" class="text-yellow-300">0</span></div>
131
  <div id="finalDish" class="text-9xl mb-12">🍲</div>
@@ -136,6 +297,9 @@
136
  </div>
137
  </div>
138
 
 
 
 
139
  <script>
140
  // Game state
141
  const gameState = {
@@ -172,7 +336,8 @@
172
  currentSequenceIndex: 0,
173
  audioContext: null,
174
  metronomeInterval: null,
175
- backgroundParticles: []
 
176
  };
177
 
178
  // DOM elements
@@ -191,6 +356,11 @@
191
  const maxComboDisplay = document.getElementById('maxCombo');
192
  const finalDishDisplay = document.getElementById('finalDish');
193
  const particlesContainer = document.getElementById('particles');
 
 
 
 
 
194
 
195
  // Initialize audio context
196
  function initAudio() {
@@ -226,7 +396,7 @@
226
  gameState.backgroundParticles = [];
227
 
228
  // Create new particles
229
- for (let i = 0; i < 30; i++) {
230
  createParticle(true);
231
  }
232
  }
@@ -236,20 +406,30 @@
236
  particle.className = 'particle';
237
 
238
  // Random properties
239
- const size = Math.random() * 6 + 2;
240
  const x = Math.random() * 100;
241
  const y = Math.random() * 100;
242
  const duration = Math.random() * 20 + 10;
243
  const delay = Math.random() * 5;
244
- const opacity = Math.random() * 0.3 + 0.1;
245
  const color = `hsl(${Math.random() * 60 + 20}, 70%, 60%)`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
 
247
- particle.style.width = `${size}px`;
248
- particle.style.height = `${size}px`;
249
  particle.style.left = `${x}%`;
250
  particle.style.top = `${y}%`;
251
- particle.style.backgroundColor = color;
252
- particle.style.borderRadius = '50%';
253
  particle.style.opacity = opacity;
254
  particle.style.animation = `float ${duration}s linear ${delay}s infinite`;
255
 
@@ -283,6 +463,10 @@
283
  gameState.metronomeInterval = setInterval(() => {
284
  playSound(880, 0.05, 'triangle');
285
  nextBeatTime += secondsPerBeat;
 
 
 
 
286
  }, secondsPerBeat * 1000);
287
  }
288
 
@@ -305,6 +489,9 @@
305
  cue.style.left = `${Math.random() * 60 + 20}%`;
306
  cue.textContent = ingredient;
307
 
 
 
 
308
  // Add to DOM and active cues array
309
  gameArea.appendChild(cue);
310
  const cueObj = {
@@ -325,6 +512,37 @@
325
  return cueObj;
326
  }
327
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
328
  // Show feedback
329
  function showFeedback(text, isGood) {
330
  feedbackText.textContent = text;
@@ -336,6 +554,14 @@
336
  // Create hit effect
337
  if (isGood) {
338
  createHitEffect(feedbackText.getBoundingClientRect());
 
 
 
 
 
 
 
 
339
  }
340
 
341
  // Hide feedback after delay
@@ -348,14 +574,14 @@
348
  function createHitEffect(rect) {
349
  const colors = ['#FFD700', '#FF6347', '#7FFFD4', '#FF69B4', '#9370DB'];
350
 
351
- for (let i = 0; i < 15; i++) {
352
  const particle = document.createElement('div');
353
  particle.className = 'particle';
354
 
355
- const size = Math.random() * 12 + 4;
356
  const color = colors[Math.floor(Math.random() * colors.length)];
357
  const angle = Math.random() * Math.PI * 2;
358
- const distance = Math.random() * 50 + 20;
359
  const duration = Math.random() * 1 + 0.5;
360
 
361
  particle.style.width = `${size}px`;
@@ -377,6 +603,91 @@
377
  setTimeout(() => particle.remove(), duration * 1000);
378
  }, 10);
379
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
380
  }
381
 
382
  // Handle successful hit
@@ -387,12 +698,17 @@
387
 
388
  // Visual feedback on the cue
389
  cue.element.classList.add('perfect-hit');
390
- cue.element.style.transform = 'scale(1.2)';
391
 
392
  setTimeout(() => {
393
  cue.element.remove();
394
  }, 200);
395
 
 
 
 
 
 
396
  // Determine hit quality
397
  let points = 0;
398
  let feedback = '';
@@ -404,6 +720,13 @@
404
  soundFreq = 1046.50; // C note
405
  playSound(soundFreq, 0.2, 'sine');
406
  playSound(soundFreq/2, 0.3, 'sine');
 
 
 
 
 
 
 
407
  } else if (Math.abs(accuracy) <= gameState.goodWindow) {
408
  points = 60;
409
  feedback = 'GREAT! οΏ½οΏ½';
@@ -429,6 +752,28 @@
429
  // Show combo if > 1
430
  if (gameState.combo > 1) {
431
  comboContainer.classList.remove('hidden');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
432
  }
433
 
434
  // Show feedback
@@ -438,6 +783,41 @@
438
  createIngredientEffect(cue);
439
  }
440
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
441
  // Create ingredient transformation effect
442
  function createIngredientEffect(cue) {
443
  const rect = cue.element.getBoundingClientRect();
@@ -457,7 +837,7 @@
457
  // Animate transformation
458
  setTimeout(() => {
459
  effect.style.transition = 'all 0.5s ease-out';
460
- effect.style.transform = 'translateY(-30px) scale(1.5)';
461
  effect.style.opacity = '0';
462
 
463
  // Change to a cooked version
@@ -495,6 +875,11 @@
495
  setTimeout(() => {
496
  cue.element.remove();
497
  }, 500);
 
 
 
 
 
498
  }
499
 
500
  // Reset combo
@@ -509,22 +894,22 @@
509
  // Create break effect
510
  if (cue.element) {
511
  const rect = cue.element.getBoundingClientRect();
512
- for (let i = 0; i < 5; i++) {
513
  const piece = document.createElement('div');
514
  piece.className = 'particle absolute text-xl';
515
  piece.textContent = cue.ingredient;
516
  piece.style.left = `${rect.left + rect.width/2}px`;
517
  piece.style.top = `${rect.top + rect.height/2}px`;
518
- piece.style.transform = `translate(${(Math.random() - 0.5) * 50}px, ${(Math.random() - 0.5) * 50}px) rotate(${Math.random() * 360}deg)`;
519
  piece.style.opacity = '0.7';
520
- piece.style.transition = 'all 0.5s ease-out';
521
 
522
  document.body.appendChild(piece);
523
 
524
  setTimeout(() => {
525
  piece.style.opacity = '0';
526
- piece.style.transform += ` translateY(30px)`;
527
- setTimeout(() => piece.remove(), 500);
528
  }, 10);
529
  }
530
  }
@@ -543,6 +928,7 @@
543
  scoreDisplay.textContent = '0';
544
  comboDisplay.textContent = '0';
545
  comboContainer.classList.add('hidden');
 
546
 
547
  // Create background particles
548
  createParticles();
@@ -607,18 +993,40 @@
607
  endScreen.classList.remove('hidden');
608
 
609
  // Celebration particles
610
- for (let i = 0; i < 50; i++) {
611
  setTimeout(() => {
612
- createParticle();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
613
  }, i * 50);
614
  }
615
  }, gameState.cueSpeed * 1000);
616
  }
617
 
618
  // Handle tap input
619
- function handleTap() {
620
  if (!gameState.isPlaying) return;
621
 
 
 
 
 
 
 
 
622
  const now = Date.now();
623
  let closestCue = null;
624
  let closestDiff = Infinity;
@@ -640,6 +1048,9 @@
640
  targetZone.classList.remove('perfect-hit');
641
  }, 300);
642
 
 
 
 
643
  // Check if tap was close enough to any cue
644
  if (closestCue && Math.abs(closestDiff) <= gameState.goodWindow * 2) {
645
  handleHit(closestCue, closestDiff);
@@ -657,6 +1068,21 @@
657
  function initGame() {
658
  initAudio();
659
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
660
  // Start button
661
  startButton.addEventListener('click', () => {
662
  startScreen.classList.add('opacity-0');
@@ -679,7 +1105,7 @@
679
  // Touch support
680
  gameArea.addEventListener('touchstart', (e) => {
681
  e.preventDefault();
682
- handleTap();
683
  });
684
  }
685
 
 
46
  #gameArea {
47
  touch-action: manipulation;
48
  background: radial-gradient(circle at center, #1a202c 0%, #111827 100%);
49
+ overflow: hidden;
50
  }
51
 
52
  .kitchen-counter {
 
77
  50% { box-shadow: 0 0 30px 15px rgba(255, 255, 255, 0.7); }
78
  100% { box-shadow: 0 0 0 0 rgba(255, 255, 255, 0); }
79
  }
80
+
81
+ /* New effects */
82
+ .ripple {
83
+ position: absolute;
84
+ border-radius: 50%;
85
+ background: rgba(255, 255, 255, 0.3);
86
+ transform: scale(0);
87
+ pointer-events: none;
88
+ animation: ripple 1s linear;
89
+ }
90
+
91
+ @keyframes ripple {
92
+ to {
93
+ transform: scale(4);
94
+ opacity: 0;
95
+ }
96
+ }
97
+
98
+ .floating-bg-element {
99
+ position: absolute;
100
+ opacity: 0.1;
101
+ animation: floatBg 30s linear infinite;
102
+ z-index: 0;
103
+ }
104
+
105
+ @keyframes floatBg {
106
+ 0% { transform: translate(0, 0) rotate(0deg); }
107
+ 25% { transform: translate(50px, 50px) rotate(5deg); }
108
+ 50% { transform: translate(100px, 0) rotate(0deg); }
109
+ 75% { transform: translate(50px, -50px) rotate(-5deg); }
110
+ 100% { transform: translate(0, 0) rotate(0deg); }
111
+ }
112
+
113
+ .combo-explosion {
114
+ position: absolute;
115
+ width: 100%;
116
+ height: 100%;
117
+ pointer-events: none;
118
+ z-index: 5;
119
+ }
120
+
121
+ .streak-light {
122
+ position: absolute;
123
+ height: 2px;
124
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.8), transparent);
125
+ transform-origin: left center;
126
+ pointer-events: none;
127
+ z-index: 4;
128
+ }
129
+
130
+ .ingredient-trail {
131
+ position: absolute;
132
+ width: 10px;
133
+ height: 10px;
134
+ border-radius: 50%;
135
+ pointer-events: none;
136
+ z-index: 3;
137
+ }
138
+
139
+ .energy-wave {
140
+ position: absolute;
141
+ width: 300px;
142
+ height: 300px;
143
+ border-radius: 50%;
144
+ background: radial-gradient(circle, rgba(255,255,255,0.2) 0%, transparent 70%);
145
+ transform: scale(0);
146
+ opacity: 1;
147
+ pointer-events: none;
148
+ animation: energyWave 1.5s ease-out forwards;
149
+ }
150
+
151
+ @keyframes energyWave {
152
+ 0% { transform: scale(0); opacity: 1; }
153
+ 100% { transform: scale(3); opacity: 0; }
154
+ }
155
+
156
+ .floating-sparkle {
157
+ position: absolute;
158
+ width: 6px;
159
+ height: 6px;
160
+ border-radius: 50%;
161
+ background-color: white;
162
+ pointer-events: none;
163
+ animation: sparkleFloat 2s ease-out forwards;
164
+ }
165
+
166
+ @keyframes sparkleFloat {
167
+ 0% { transform: translate(0, 0) scale(1); opacity: 1; }
168
+ 100% { transform: translate(random(100) - 50px, -100px) scale(0); opacity: 0; }
169
+ }
170
+
171
+ .screen-flash {
172
+ position: fixed;
173
+ top: 0;
174
+ left: 0;
175
+ width: 100%;
176
+ height: 100%;
177
+ background-color: white;
178
+ opacity: 0;
179
+ pointer-events: none;
180
+ z-index: 10;
181
+ }
182
+
183
+ .combo-streak {
184
+ position: absolute;
185
+ width: 100%;
186
+ height: 100%;
187
+ background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%);
188
+ pointer-events: none;
189
+ z-index: 2;
190
+ }
191
+
192
+ .kitchen-light {
193
+ position: absolute;
194
+ width: 100%;
195
+ height: 100%;
196
+ background: radial-gradient(circle at 50% 30%, rgba(255,215,0,0.1) 0%, transparent 70%);
197
+ pointer-events: none;
198
+ z-index: 1;
199
+ animation: kitchenLightPulse 2s infinite alternate;
200
+ }
201
+
202
+ @keyframes kitchenLightPulse {
203
+ 0% { opacity: 0.3; }
204
+ 100% { opacity: 0.7; }
205
+ }
206
+
207
+ .perfect-ring {
208
+ position: absolute;
209
+ border-radius: 50%;
210
+ border: 3px solid rgba(255,255,255,0.8);
211
+ transform: scale(0);
212
+ pointer-events: none;
213
+ animation: perfectRing 0.8s ease-out forwards;
214
+ }
215
+
216
+ @keyframes perfectRing {
217
+ 0% { transform: scale(0); opacity: 1; }
218
+ 100% { transform: scale(3); opacity: 0; }
219
+ }
220
  </style>
221
  </head>
222
  <body class="bg-gray-900 text-white font-sans overflow-hidden">
223
  <!-- Start Screen -->
224
  <div id="startScreen" class="fixed inset-0 flex flex-col items-center justify-center bg-gradient-to-br from-gray-900 to-gray-800 z-10 transition-opacity duration-500">
225
+ <div id="startScreenBg" class="absolute inset-0 overflow-hidden">
226
+ <!-- Floating background elements -->
227
+ <div class="floating-bg-element text-6xl" style="top:20%; left:10%;">🍳</div>
228
+ <div class="floating-bg-element text-6xl" style="top:30%; left:70%;">πŸ₯˜</div>
229
+ <div class="floating-bg-element text-6xl" style="top:60%; left:20%;">πŸ•</div>
230
+ <div class="floating-bg-element text-6xl" style="top:70%; left:80%;">🍣</div>
231
+ </div>
232
+
233
+ <div class="text-center mb-12 relative z-10">
234
  <h1 class="text-7xl font-bold mb-4 text-yellow-400 glow">🍳 RHYTHM CHEF</h1>
235
  <h2 class="text-4xl mb-6 text-yellow-300 glow">Beat Bites Deluxe</h2>
236
  <div class="text-xl text-gray-300 max-w-md mx-auto">
237
  Tap the ingredients in rhythm to cook up perfect dishes!
238
  </div>
239
  </div>
240
+ <button id="startButton" class="bg-gradient-to-r from-yellow-500 to-yellow-600 hover:from-yellow-400 hover:to-yellow-500 text-4xl text-gray-900 font-bold py-5 px-16 rounded-full transition-all transform hover:scale-105 shadow-lg glow relative z-10">
241
  START COOKING
242
  </button>
243
+ <div class="absolute bottom-8 text-gray-400 text-sm z-10">
244
  Tap the beat when ingredients reach the counter
245
  </div>
246
  </div>
247
 
248
  <!-- Game Screen -->
249
  <div id="gameScreen" class="fixed inset-0 hidden flex flex-col">
250
+ <!-- Kitchen ambient light -->
251
+ <div class="kitchen-light"></div>
252
+
253
  <!-- Score Display -->
254
+ <div class="flex justify-between px-8 pt-6 relative z-10">
255
  <div class="text-4xl font-bold score-glow">
256
  πŸ† <span id="score">0</span>
257
  </div>
 
265
  <!-- Floating particles background -->
266
  <div id="particles"></div>
267
 
268
+ <!-- Combo streak effect -->
269
+ <div id="comboStreak" class="combo-streak hidden"></div>
270
+
271
  <!-- Target Zone (Kitchen Counter) -->
272
  <div id="targetZone" class="kitchen-counter absolute left-0 right-0 h-24 rounded-t-3xl flex items-center justify-center" style="bottom: 20%;">
273
  <div class="w-full h-1 bg-yellow-300 bg-opacity-50 rounded-full mx-8"></div>
 
275
 
276
  <!-- Feedback Text -->
277
  <div id="feedbackText" class="absolute left-1/2 transform -translate-x-1/2 text-6xl font-bold text-center opacity-0" style="bottom: 30%;"></div>
278
+
279
+ <!-- Combo explosion container -->
280
+ <div id="comboExplosion" class="combo-explosion"></div>
281
+
282
+ <!-- Energy waves container -->
283
+ <div id="energyWaves"></div>
284
  </div>
285
  </div>
286
 
287
  <!-- End Screen -->
288
  <div id="endScreen" class="fixed inset-0 hidden flex flex-col items-center justify-center bg-gray-900 bg-opacity-95 z-20">
289
+ <div class="text-center relative">
290
  <h2 class="text-6xl font-bold mb-8 text-yellow-400 glow">DISH COMPLETE! πŸŽ‰</h2>
291
  <div class="text-5xl mb-8">Final Score: <span id="finalScore" class="text-yellow-300">0</span></div>
292
  <div id="finalDish" class="text-9xl mb-12">🍲</div>
 
297
  </div>
298
  </div>
299
 
300
+ <!-- Screen flash effect -->
301
+ <div id="screenFlash" class="screen-flash"></div>
302
+
303
  <script>
304
  // Game state
305
  const gameState = {
 
336
  currentSequenceIndex: 0,
337
  audioContext: null,
338
  metronomeInterval: null,
339
+ backgroundParticles: [],
340
+ lastTapPosition: { x: 0, y: 0 }
341
  };
342
 
343
  // DOM elements
 
356
  const maxComboDisplay = document.getElementById('maxCombo');
357
  const finalDishDisplay = document.getElementById('finalDish');
358
  const particlesContainer = document.getElementById('particles');
359
+ const comboExplosion = document.getElementById('comboExplosion');
360
+ const comboStreak = document.getElementById('comboStreak');
361
+ const energyWaves = document.getElementById('energyWaves');
362
+ const screenFlash = document.getElementById('screenFlash');
363
+ const startScreenBg = document.getElementById('startScreenBg');
364
 
365
  // Initialize audio context
366
  function initAudio() {
 
396
  gameState.backgroundParticles = [];
397
 
398
  // Create new particles
399
+ for (let i = 0; i < 50; i++) {
400
  createParticle(true);
401
  }
402
  }
 
406
  particle.className = 'particle';
407
 
408
  // Random properties
409
+ const size = Math.random() * 10 + 2;
410
  const x = Math.random() * 100;
411
  const y = Math.random() * 100;
412
  const duration = Math.random() * 20 + 10;
413
  const delay = Math.random() * 5;
414
+ const opacity = Math.random() * 0.5 + 0.1;
415
  const color = `hsl(${Math.random() * 60 + 20}, 70%, 60%)`;
416
+ const shape = Math.random() > 0.7 ? 'text' : 'circle';
417
+
418
+ if (shape === 'text') {
419
+ const emojis = ['✨', '🌟', '⭐', '⚑', 'πŸ’«', 'πŸ”₯', '🍳', 'πŸ₯˜', '🍲'];
420
+ particle.textContent = emojis[Math.floor(Math.random() * emojis.length)];
421
+ particle.style.fontSize = `${size}px`;
422
+ particle.style.width = 'auto';
423
+ particle.style.height = 'auto';
424
+ } else {
425
+ particle.style.width = `${size}px`;
426
+ particle.style.height = `${size}px`;
427
+ particle.style.backgroundColor = color;
428
+ particle.style.borderRadius = '50%';
429
+ }
430
 
 
 
431
  particle.style.left = `${x}%`;
432
  particle.style.top = `${y}%`;
 
 
433
  particle.style.opacity = opacity;
434
  particle.style.animation = `float ${duration}s linear ${delay}s infinite`;
435
 
 
463
  gameState.metronomeInterval = setInterval(() => {
464
  playSound(880, 0.05, 'triangle');
465
  nextBeatTime += secondsPerBeat;
466
+
467
+ // Visual metronome effect
468
+ createEnergyWave(targetZone.getBoundingClientRect().left + targetZone.offsetWidth / 2,
469
+ targetZone.getBoundingClientRect().top + targetZone.offsetHeight / 2);
470
  }, secondsPerBeat * 1000);
471
  }
472
 
 
489
  cue.style.left = `${Math.random() * 60 + 20}%`;
490
  cue.textContent = ingredient;
491
 
492
+ // Add trail effect
493
+ createIngredientTrail(cue);
494
+
495
  // Add to DOM and active cues array
496
  gameArea.appendChild(cue);
497
  const cueObj = {
 
512
  return cueObj;
513
  }
514
 
515
+ // Create ingredient trail effect
516
+ function createIngredientTrail(cue) {
517
+ const trailInterval = setInterval(() => {
518
+ if (!cue.parentElement) {
519
+ clearInterval(trailInterval);
520
+ return;
521
+ }
522
+
523
+ const rect = cue.getBoundingClientRect();
524
+ const trail = document.createElement('div');
525
+ trail.className = 'ingredient-trail';
526
+ trail.style.left = `${rect.left + rect.width / 2}px`;
527
+ trail.style.top = `${rect.top + rect.height / 2}px`;
528
+ trail.style.backgroundColor = `hsl(${Math.random() * 60 + 20}, 80%, 60%)`;
529
+ trail.style.opacity = Math.random() * 0.6 + 0.2;
530
+ trail.style.transform = `scale(${Math.random() * 0.5 + 0.5})`;
531
+
532
+ document.body.appendChild(trail);
533
+
534
+ setTimeout(() => {
535
+ trail.style.transition = 'all 0.5s ease-out';
536
+ trail.style.opacity = '0';
537
+ trail.style.transform = 'scale(0)';
538
+ setTimeout(() => trail.remove(), 500);
539
+ }, 10);
540
+ }, 50);
541
+
542
+ // Clean up interval when cue is removed
543
+ cue.dataset.trailInterval = trailInterval;
544
+ }
545
+
546
  // Show feedback
547
  function showFeedback(text, isGood) {
548
  feedbackText.textContent = text;
 
554
  // Create hit effect
555
  if (isGood) {
556
  createHitEffect(feedbackText.getBoundingClientRect());
557
+
558
+ // Add ripple effect
559
+ createRippleEffect(gameState.lastTapPosition.x, gameState.lastTapPosition.y);
560
+
561
+ // Add perfect ring for perfect hits
562
+ if (text.includes('PERFECT')) {
563
+ createPerfectRing(gameState.lastTapPosition.x, gameState.lastTapPosition.y);
564
+ }
565
  }
566
 
567
  // Hide feedback after delay
 
574
  function createHitEffect(rect) {
575
  const colors = ['#FFD700', '#FF6347', '#7FFFD4', '#FF69B4', '#9370DB'];
576
 
577
+ for (let i = 0; i < 25; i++) {
578
  const particle = document.createElement('div');
579
  particle.className = 'particle';
580
 
581
+ const size = Math.random() * 16 + 4;
582
  const color = colors[Math.floor(Math.random() * colors.length)];
583
  const angle = Math.random() * Math.PI * 2;
584
+ const distance = Math.random() * 100 + 30;
585
  const duration = Math.random() * 1 + 0.5;
586
 
587
  particle.style.width = `${size}px`;
 
603
  setTimeout(() => particle.remove(), duration * 1000);
604
  }, 10);
605
  }
606
+
607
+ // Add floating sparkles
608
+ for (let i = 0; i < 10; i++) {
609
+ createFloatingSparkle(rect.left + rect.width / 2, rect.top + rect.height / 2);
610
+ }
611
+ }
612
+
613
+ // Create ripple effect
614
+ function createRippleEffect(x, y) {
615
+ const ripple = document.createElement('div');
616
+ ripple.className = 'ripple';
617
+ ripple.style.left = `${x}px`;
618
+ ripple.style.top = `${y}px`;
619
+ ripple.style.width = '50px';
620
+ ripple.style.height = '50px';
621
+ ripple.style.backgroundColor = `rgba(255, 255, 255, ${Math.random() * 0.2 + 0.1})`;
622
+
623
+ document.body.appendChild(ripple);
624
+
625
+ setTimeout(() => {
626
+ ripple.remove();
627
+ }, 1000);
628
+ }
629
+
630
+ // Create perfect ring effect
631
+ function createPerfectRing(x, y) {
632
+ const ring = document.createElement('div');
633
+ ring.className = 'perfect-ring';
634
+ ring.style.left = `${x}px`;
635
+ ring.style.top = `${y}px`;
636
+ ring.style.width = '50px';
637
+ ring.style.height = '50px';
638
+
639
+ document.body.appendChild(ring);
640
+
641
+ setTimeout(() => {
642
+ ring.remove();
643
+ }, 800);
644
+ }
645
+
646
+ // Create floating sparkle
647
+ function createFloatingSparkle(x, y) {
648
+ const sparkle = document.createElement('div');
649
+ sparkle.className = 'floating-sparkle';
650
+ sparkle.style.left = `${x}px`;
651
+ sparkle.style.top = `${y}px`;
652
+ sparkle.style.backgroundColor = `hsl(${Math.random() * 60 + 20}, 100%, 80%)`;
653
+
654
+ document.body.appendChild(sparkle);
655
+
656
+ setTimeout(() => {
657
+ sparkle.remove();
658
+ }, 2000);
659
+ }
660
+
661
+ // Create energy wave
662
+ function createEnergyWave(x, y) {
663
+ const wave = document.createElement('div');
664
+ wave.className = 'energy-wave';
665
+ wave.style.left = `${x - 150}px`;
666
+ wave.style.top = `${y - 150}px`;
667
+
668
+ energyWaves.appendChild(wave);
669
+
670
+ setTimeout(() => {
671
+ wave.remove();
672
+ }, 1500);
673
+ }
674
+
675
+ // Create streak light effect
676
+ function createStreakLight(x, y, angle, length) {
677
+ const light = document.createElement('div');
678
+ light.className = 'streak-light';
679
+ light.style.left = `${x}px`;
680
+ light.style.top = `${y}px`;
681
+ light.style.width = `${length}px`;
682
+ light.style.transform = `rotate(${angle}rad)`;
683
+
684
+ document.body.appendChild(light);
685
+
686
+ setTimeout(() => {
687
+ light.style.opacity = '0';
688
+ light.style.transition = 'opacity 0.5s ease-out';
689
+ setTimeout(() => light.remove(), 500);
690
+ }, 10);
691
  }
692
 
693
  // Handle successful hit
 
698
 
699
  // Visual feedback on the cue
700
  cue.element.classList.add('perfect-hit');
701
+ cue.element.style.transform = 'scale(1.5)';
702
 
703
  setTimeout(() => {
704
  cue.element.remove();
705
  }, 200);
706
 
707
+ // Clear trail interval
708
+ if (cue.element.dataset.trailInterval) {
709
+ clearInterval(parseInt(cue.element.dataset.trailInterval));
710
+ }
711
+
712
  // Determine hit quality
713
  let points = 0;
714
  let feedback = '';
 
720
  soundFreq = 1046.50; // C note
721
  playSound(soundFreq, 0.2, 'sine');
722
  playSound(soundFreq/2, 0.3, 'sine');
723
+
724
+ // Screen flash for perfect hits
725
+ screenFlash.style.opacity = '0.3';
726
+ screenFlash.style.transition = 'opacity 0.3s ease-out';
727
+ setTimeout(() => {
728
+ screenFlash.style.opacity = '0';
729
+ }, 300);
730
  } else if (Math.abs(accuracy) <= gameState.goodWindow) {
731
  points = 60;
732
  feedback = 'GREAT! οΏ½οΏ½';
 
752
  // Show combo if > 1
753
  if (gameState.combo > 1) {
754
  comboContainer.classList.remove('hidden');
755
+
756
+ // Combo streak effect
757
+ if (gameState.combo % 5 === 0) {
758
+ comboStreak.classList.remove('hidden');
759
+ setTimeout(() => {
760
+ comboStreak.classList.add('hidden');
761
+ }, 300);
762
+
763
+ // Combo explosion for every 5 hits
764
+ if (gameState.combo % 10 === 0) {
765
+ createComboExplosion();
766
+ }
767
+ }
768
+
769
+ // Streak lights for high combos
770
+ if (gameState.combo > 3) {
771
+ for (let i = 0; i < 3; i++) {
772
+ const angle = Math.random() * Math.PI * 2;
773
+ const length = Math.random() * 200 + 100;
774
+ createStreakLight(gameState.lastTapPosition.x, gameState.lastTapPosition.y, angle, length);
775
+ }
776
+ }
777
  }
778
 
779
  // Show feedback
 
783
  createIngredientEffect(cue);
784
  }
785
 
786
+ // Create combo explosion effect
787
+ function createComboExplosion() {
788
+ comboExplosion.innerHTML = '';
789
+
790
+ for (let i = 0; i < 30; i++) {
791
+ const particle = document.createElement('div');
792
+ particle.className = 'particle';
793
+
794
+ const size = Math.random() * 20 + 10;
795
+ const color = `hsl(${Math.random() * 60 + 20}, 100%, 70%)`;
796
+ const angle = Math.random() * Math.PI * 2;
797
+ const distance = Math.random() * 300 + 100;
798
+ const duration = Math.random() * 1 + 0.5;
799
+
800
+ particle.style.width = `${size}px`;
801
+ particle.style.height = `${size}px`;
802
+ particle.style.left = '50%';
803
+ particle.style.top = '50%';
804
+ particle.style.backgroundColor = color;
805
+ particle.style.borderRadius = '50%';
806
+ particle.style.opacity = '0.8';
807
+ particle.style.transform = `translate(-50%, -50%) translate(${Math.cos(angle) * distance}px, ${Math.sin(angle) * distance}px)`;
808
+ particle.style.transition = `all ${duration}s ease-out`;
809
+ particle.style.boxShadow = `0 0 ${size/2}px ${color}`;
810
+
811
+ comboExplosion.appendChild(particle);
812
+
813
+ setTimeout(() => {
814
+ particle.style.opacity = '0';
815
+ particle.style.transform += ` scale(0.5)`;
816
+ setTimeout(() => particle.remove(), duration * 1000);
817
+ }, 10);
818
+ }
819
+ }
820
+
821
  // Create ingredient transformation effect
822
  function createIngredientEffect(cue) {
823
  const rect = cue.element.getBoundingClientRect();
 
837
  // Animate transformation
838
  setTimeout(() => {
839
  effect.style.transition = 'all 0.5s ease-out';
840
+ effect.style.transform = 'translateY(-50px) scale(2)';
841
  effect.style.opacity = '0';
842
 
843
  // Change to a cooked version
 
875
  setTimeout(() => {
876
  cue.element.remove();
877
  }, 500);
878
+
879
+ // Clear trail interval
880
+ if (cue.element.dataset.trailInterval) {
881
+ clearInterval(parseInt(cue.element.dataset.trailInterval));
882
+ }
883
  }
884
 
885
  // Reset combo
 
894
  // Create break effect
895
  if (cue.element) {
896
  const rect = cue.element.getBoundingClientRect();
897
+ for (let i = 0; i < 8; i++) {
898
  const piece = document.createElement('div');
899
  piece.className = 'particle absolute text-xl';
900
  piece.textContent = cue.ingredient;
901
  piece.style.left = `${rect.left + rect.width/2}px`;
902
  piece.style.top = `${rect.top + rect.height/2}px`;
903
+ piece.style.transform = `translate(${(Math.random() - 0.5) * 80}px, ${(Math.random() - 0.5) * 80}px) rotate(${Math.random() * 360}deg)`;
904
  piece.style.opacity = '0.7';
905
+ piece.style.transition = 'all 0.8s ease-out';
906
 
907
  document.body.appendChild(piece);
908
 
909
  setTimeout(() => {
910
  piece.style.opacity = '0';
911
+ piece.style.transform += ` translateY(50px)`;
912
+ setTimeout(() => piece.remove(), 800);
913
  }, 10);
914
  }
915
  }
 
928
  scoreDisplay.textContent = '0';
929
  comboDisplay.textContent = '0';
930
  comboContainer.classList.add('hidden');
931
+ comboStreak.classList.add('hidden');
932
 
933
  // Create background particles
934
  createParticles();
 
993
  endScreen.classList.remove('hidden');
994
 
995
  // Celebration particles
996
+ for (let i = 0; i < 100; i++) {
997
  setTimeout(() => {
998
+ const particle = createParticle();
999
+ particle.style.position = 'fixed';
1000
+ particle.style.left = `${Math.random() * 100}%`;
1001
+ particle.style.top = `${Math.random() * 100}%`;
1002
+ particle.style.fontSize = `${Math.random() * 30 + 20}px`;
1003
+ particle.style.opacity = '0.8';
1004
+ particle.style.animation = `float ${Math.random() * 3 + 2}s ease-out forwards`;
1005
+
1006
+ const emojis = ['✨', '🌟', '⭐', '⚑', 'πŸ’«', 'πŸ”₯', 'πŸŽ‰', '🎊', 'πŸ₯³'];
1007
+ particle.textContent = emojis[Math.floor(Math.random() * emojis.length)];
1008
+
1009
+ endScreen.appendChild(particle);
1010
+
1011
+ setTimeout(() => {
1012
+ particle.remove();
1013
+ }, 3000);
1014
  }, i * 50);
1015
  }
1016
  }, gameState.cueSpeed * 1000);
1017
  }
1018
 
1019
  // Handle tap input
1020
+ function handleTap(e) {
1021
  if (!gameState.isPlaying) return;
1022
 
1023
+ // Store tap position for effects
1024
+ const rect = gameArea.getBoundingClientRect();
1025
+ gameState.lastTapPosition = {
1026
+ x: (e.clientX || e.touches[0].clientX) - rect.left,
1027
+ y: (e.clientY || e.touches[0].clientY) - rect.top
1028
+ };
1029
+
1030
  const now = Date.now();
1031
  let closestCue = null;
1032
  let closestDiff = Infinity;
 
1048
  targetZone.classList.remove('perfect-hit');
1049
  }, 300);
1050
 
1051
+ // Create energy wave at tap position
1052
+ createEnergyWave(gameState.lastTapPosition.x, gameState.lastTapPosition.y);
1053
+
1054
  // Check if tap was close enough to any cue
1055
  if (closestCue && Math.abs(closestDiff) <= gameState.goodWindow * 2) {
1056
  handleHit(closestCue, closestDiff);
 
1068
  function initGame() {
1069
  initAudio();
1070
 
1071
+ // Add floating elements to start screen
1072
+ for (let i = 0; i < 10; i++) {
1073
+ const element = document.createElement('div');
1074
+ element.className = 'floating-bg-element text-4xl';
1075
+ element.style.left = `${Math.random() * 100}%`;
1076
+ element.style.top = `${Math.random() * 100}%`;
1077
+ element.style.animationDuration = `${Math.random() * 30 + 20}s`;
1078
+ element.style.animationDelay = `${Math.random() * 10}s`;
1079
+
1080
+ const emojis = ['🍳', 'πŸ₯˜', 'πŸ•', 'πŸ”', '🍟', '🌭', '🍿', 'πŸ§‚', 'πŸ₯—', '🍣'];
1081
+ element.textContent = emojis[Math.floor(Math.random() * emojis.length)];
1082
+
1083
+ startScreenBg.appendChild(element);
1084
+ }
1085
+
1086
  // Start button
1087
  startButton.addEventListener('click', () => {
1088
  startScreen.classList.add('opacity-0');
 
1105
  // Touch support
1106
  gameArea.addEventListener('touchstart', (e) => {
1107
  e.preventDefault();
1108
+ handleTap(e);
1109
  });
1110
  }
1111
 
prompts.txt CHANGED
@@ -1,2 +1,3 @@
1
  Okay, here is a detailed, implementation-grade plan for building an interactive demonstrator for the core game mechanics of **Rhythm Chef: Beat Bites**. This focuses on creating a minimal viable product (MVP) specifically for user feedback on the core rhythm interaction feel, keeping the codebase limited. **Assumptions:** * **Engine:** Unity (common choice for hypercasual, good for rapid prototyping). * **Language:** C#. * **Target Platform:** Android (easy for distributing APKs for testing). * **Input Focus:** Start with **Tap** only for simplicity. Hold/Swipe can be added later if the Tap feels good. **I. Demonstrator Objectives** 1. Implement the core rhythm interaction: spawning cues, moving cues, detecting timed player input within a target zone. 2. Provide immediate, clear visual and audio feedback for successful hits and misses. 3. Synchronize cue movement and required input timing to a consistent beat (can be a simple metronome track or internal timer). 4. Allow a user to play through a short, predefined sequence of cues. 5. Keep the scope strictly limited to the core mechanic loop for fast iteration and focused feedback. **II. Scope Definition** * **IN SCOPE:** * Single, non-scrolling conveyor belt or lane for cues. * One type of cue requiring a **Tap** input. * One clearly defined target zone. * Precise timing mechanism for cue spawning and hit detection. * Simple visual representation of cues (e.g., colored circles/squares representing ingredients/actions). * Visual feedback (e.g., color change, simple particle effect, text popup like "Perfect!"/"Miss!"). * Basic audio feedback (hit sound, miss sound, beat/metronome sound). * A predefined, short sequence (~15-30 seconds) of Tap cues. * Minimal UI: Start Button, potentially a simple score/combo counter (optional but helpful). * **OUT OF SCOPE:** * Multiple lanes or complex patterns. * Hold or Swipe input types. * Multiple cue types/actions (chop, fry, etc.). * Any meta-game (restaurant, currency, upgrades). * Scoring beyond basic hit/miss feedback (no stars, complex calculations). * Multiple songs or difficulty levels. * Polished art assets (use placeholders). * Advanced UI, menus, settings. * Saving/loading progress. * Performance optimization beyond basic functionality. **III. Key Components & Implementation Details** 1. **`GameManager.cs`** * **Purpose:** Controls the overall state, timing, and sequence playback. * **Properties:** * `float bpm`: Beats per minute for the rhythm. * `float cueSpeed`: Speed at which cues travel towards the target. * `float targetZonePosition`: Y-coordinate (or X if horizontal) of the target zone center. * `float spawnPosition`: Y-coordinate (or X) where cues appear. * `GameObject cuePrefab`: Prefab for the visual cue object. * `Transform cueSpawnPoint`: Transform where cues are instantiated. * `AudioSource metronomeSource`: Optional, for playing a beat sound. * `List<CueData> sequence`: Holds the predefined sequence of cues (timing). * `float songStartTime`: Time when the sequence began (using `AudioSettings.dspTime` or `Time.timeSinceLevelLoad`). * `int currentSequenceIndex`: Tracks the next cue to spawn. * `bool isPlaying`: Game state flag. * **Methods:** * `StartSequence()`: Initializes timing, resets index, sets `isPlaying = true`. Starts metronome if used. * `Update()`: * If `isPlaying`, check `sequence` if it's time to spawn the `currentSequenceIndex` cue based on `bpm` and `songStartTime`. * If spawning, instantiate `cuePrefab` at `cueSpawnPoint`, calculate its `targetTime` (arrival time at target zone), and pass necessary data to the cue's script. Increment `currentSequenceIndex`. * Handles end of sequence. * `StopSequence()`: Sets `isPlaying = false`. 2. **`CueData.cs` (or Struct)** * **Purpose:** Simple data structure to define a single cue in the sequence. * **Properties:** * `float beatTimestamp`: The beat number (e.g., 1, 1.5, 2) within the sequence when this cue should *hit* the target zone. * `CueType type`: Enum (e.g., `Tap`). (Initially only Tap needed). 3. **`CueObject.cs` (attached to `cuePrefab`)** * **Purpose:** Represents a single moving cue. * **Properties:** * `float speed`: Movement speed (set by `GameManager`). * `float targetTime`: The exact game time (`Time.timeSinceLevelLoad` or `dspTime`) this cue should ideally be hit. * `bool isHit`: Flag to prevent multiple hits. * `bool canBeHit`: Flag to indicate if it's currently within the hittable window around the target zone. * **Methods:** * `Initialize(float targetTime, float speed)`: Called by `GameManager` on spawn. * `Update()`: * Move the cue downwards (or towards the target) at `speed * Time.deltaTime`. * Check if the cue has passed the target zone *without* being hit and *after* its hittable window - trigger a Miss condition if so and destroy/disable self. * `OnTriggerEnter/Exit2D(Collider2D other)`: If using physics triggers for the target zone, set `canBeHit = true/false`. * `ProcessHit()`: Called by `InputHandler` when a hit is registered on this cue. Sets `isHit = true`, triggers success feedback, potentially disables the cue visually, and schedules destruction. 4. **`TargetZone.cs` (attached to a GameObject with a Collider2D)** * **Purpose:** Defines the area where input is registered and cues are evaluated. * **Properties:** * `float perfectWindow`: Time window (+/- seconds) for a perfect hit. * `float okWindow`: Time window (+/- seconds) for an acceptable (non-miss) hit. (Keep simple first: just Perfect/Miss). * **Methods:** * `OnTriggerEnter2D/Exit2D(Collider2D other)`: Detects `CueObject` entering/leaving the zone's collider. Could be used by `CueObject` to set its `canBeHit` flag. * **Note:** Hit timing validation logic might live more centrally in `InputHandler` or `GameManager` rather than distributed here. 5. **`InputHandler.cs`** * **Purpose:** Detects player input and checks if it corresponds to a hittable cue. * **Properties:** * `TargetZone targetZone`: Reference to the target zone script/object. * `LayerMask cueLayer`: Physics layer for cues. * **Methods:** * `Update()`: * Check for Tap input (`Input.GetMouseButtonDown(0)` or `Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began`). * If Tap detected: * Determine the current game time (`Time.timeSinceLevelLoad` or `AudioSettings.dspTime`). * Find the "closest" active `CueObject` that is currently `canBeHit` (e.g., using Physics2D overlap checks near the target zone, or iterating through active cues and checking position/timing). * If a potential cue is found: * Calculate `timeDifference = currentTime - cue.targetTime`. * If `Mathf.Abs(timeDifference) <= targetZone.perfectWindow`: * Call `cue.ProcessHit()`. * Trigger "Perfect" feedback via `FeedbackManager`. * Else (if outside window but maybe an OK window exists later): * Trigger "Miss" feedback via `FeedbackManager` (or OK if implementing). * Potentially destroy/disable the cue to prevent late hits. * Else (no cue was hittable): * Optional: Trigger a generic "Miss" feedback for tapping empty space. 6. **`FeedbackManager.cs` (Singleton or easily accessible)** * **Purpose:** Centralized handler for triggering visual/audio feedback. * **Properties:** * `GameObject perfectHitEffectPrefab`: Particle effect/animation for perfect hits. * `GameObject missEffectPrefab`: Effect for misses. * `AudioClip hitSound`: Sound for successful hit. * `AudioClip missSound`: Sound for miss/error. * `AudioSource feedbackAudioSource`: Source to play feedback sounds. * `TextMeshProUGUI feedbackText`: UI Text element to display "Perfect!"/"Miss!". * **Methods:** * `ShowHitFeedback(Vector3 position)`: Instantiate `perfectHitEffectPrefab` at `position`, play `hitSound`, show "Perfect!" text briefly. * `ShowMissFeedback(Vector3 position)`: Instantiate `missEffectPrefab` at `position`, play `missSound`, show "Miss!" text briefly. **IV. Timing Implementation (CRITICAL)** * **Consistency is Key:** Use a consistent time source. * **Option A (Simpler):** `Time.timeSinceLevelLoad`. Easier for basic logic but can drift slightly from audio. Good enough for a demonstrator. * **Option B (More Accurate):** `AudioSettings.dspTime`. Provides highly accurate timing synced with the audio engine. Requires careful handling, especially when scheduling future events based on audio playback. * **Calculations:** * Convert `bpm` to seconds per beat (`60f / bpm`). * Calculate cue `targetTime`: `songStartTime + cue.beatTimestamp * secondsPerBeat`. * Calculate spawn time: `targetTime - travelDuration`, where `travelDuration` is `distance / cueSpeed`. Spawn the cue at this calculated spawn time. **V. UI Implementation (Minimal)** * Canvas with: * `Button` to call `GameManager.StartSequence()`. * `TextMeshProUGUI` (optional) for Score/Combo (incremented in `FeedbackManager` on hit, reset on miss). * `TextMeshProUGUI` for "Perfect!"/"Miss!" feedback text (controlled by `FeedbackManager`). **VI. Placeholder Assets** * **Cue:** Simple white Circle or Square sprite. * **Target Zone:** Semi-transparent rectangle/line across the lane. * **Hit Effect:** Simple particle burst (e.g., Unity's default particle system emitting a few sparks) or a quick scaling/fading circle. * **Miss Effect:** Red flash or different particle effect. * **Audio:** * Metronome: Simple "tick" sound. * Hit Sound: Short, satisfying "click" or "pop". * Miss Sound: Dull "thud" or "buzz". **VII. Build & Test Plan** 1. Implement core components (`GameManager`, `CueObject`, `InputHandler`, `TargetZone`, `FeedbackManager`). 2. Define a simple `sequence` in `GameManager` (e.g., 10 taps on consecutive beats). 3. Use precise timing based on `Time.timeSinceLevelLoad` initially. 4. Integrate basic visual and audio feedback. 5. Test internally: Does it *feel* responsive? Is the timing right? 6. Refine timing windows (`perfectWindow`) based on feel. 7. Build an Android APK. 8. Distribute APK to testers. 9. Gather feedback specifically on: * Timing sensitivity (too strict, too lenient?). * Clarity of visual cues. * Effectiveness of feedback (did they know if they hit/missed?). * Overall satisfaction/fun of the core interaction. **VIII. Success Criteria for Demonstrator** * The demonstrator runs smoothly on a target Android device. * Cues spawn and travel predictably, synchronized with the beat. * User taps near the target zone trigger immediate hit/miss feedback. * Feedback (visual and audio) is clear and correctly corresponds to input timing accuracy. * Testers can understand the core mechanic and provide feedback on its "feel" within 5 minutes of playing. * The codebase is minimal and focused solely on the described scope. Okay, here's an ASCII art representation of the UI and user flow for the **Rhythm Chef: Beat Bites** core mechanics demonstrator. **1. User Flow Diagram** ```ascii +-------------------+ +----------------------+ +----------------------+ | Start Screen | ---+->| Gameplay Loop |---+->| End Screen (Simple)| | (Title, [Start]) | User | (Cues, Target, Input)| User | (Score?, [Restart])| +-------------------+ Taps | | Finishes Sequence +----------------------+ Start +--<-------------------+ Or Fails | (Optional) | | | | Back to Start Screen | +----------------------+ +----------------------+ ``` **2. UI Mockups (ASCII Art)** **A. Start Screen** ```ascii +-----------------------------------------+ | | | // RHYTHM CHEF: BEAT BITES // | | (Core Demo) | | | | | | | | | | +-----------+ | | | [ START ]| | | +-----------+ | | | | | +-----------------------------------------+ User taps [ START ] --> Transitions to Gameplay Screen ``` **B. Gameplay Screen (Mid-Sequence)** * Imagine cues `(*)` moving downwards `v` towards the `TARGET ZONE`. * The player needs to tap when a cue is inside the `TARGET ZONE`. ```ascii +-----------------------------------------+ | SCORE: 005 COMBO: 3x | <--- Optional Score/Combo Display |-----------------------------------------| | | | | | (*) | <--- Incoming Cue 1 | v | | | | | | (*) | <--- Incoming Cue 2 | v | | | | ===================================== | \ | | TARGET ZONE | | <--- The Area to Tap In | ===================================== | / | v | | (*) | <--- Cue that just passed (or was missed) | | | | | | |-----------------------------------------| | FEEDBACK: | <--- Area for text feedback +-----------------------------------------+ ``` **C. Gameplay Screen (Moment of Tap - Perfect Hit)** * Player taps as `(*)` enters the `TARGET ZONE`. * Visual & text feedback appears. ```ascii +-----------------------------------------+ | SCORE: 006 COMBO: 4x | <--- Score/Combo Updated |-----------------------------------------| | | | | | (*) | | v | | | | | | (*) | | v | | | | ===================================== | | | > > > PERFECT! < < < | | <--- Cue hit inside, feedback shown | ===================================== | | | | | (Effect) | <--- Visual effect (e.g., ASCII explosion *`*`) | | | | |-----------------------------------------| | FEEDBACK: Perfect! | <--- Text feedback updated +-----------------------------------------+ ``` **D. Gameplay Screen (Moment of Tap - Miss)** * Player taps too early/late, or misses a cue. ```ascii +-----------------------------------------+ | SCORE: 006 COMBO: 0x | <--- Combo Reset |-----------------------------------------| | | | | | (*) | | v | | | | | | (*) | | v | | | | ===================================== | | | TARGET ZONE | | | ===================================== | | v | | (X) | <--- Missed cue indication / effect | | | | |-----------------------------------------| | FEEDBACK: Miss! | <--- Text feedback updated +-----------------------------------------+ ``` **E. End Screen (Simple Demo End)** * Appears after the predefined sequence finishes. ```ascii +-----------------------------------------+ | | | SEQUENCE COMPLETE! | | | | (Final Score: 025) | <--- Optional final score | | | | | +-------------+ | | | [ RESTART ] | | | +-------------+ | | | | | +-----------------------------------------+ User taps [ RESTART ] --> Transitions back to Gameplay Screen (restarts sequence) (Or could go back to the Start Screen) ``` This ASCII representation outlines the essential visual elements and the flow between them for the core mechanics demonstrator, focusing on clarity for user feedback on the rhythm interaction. Okay, here are specific pixel-based dimensions and positions for the UI elements based on a **reference screen resolution of 1080x1920 pixels (Width x Height - Portrait Orientation)**. **Important Considerations:** * **Reference Only:** These are *fixed pixel values* for the specified reference resolution. In a real implementation (e.g., using Unity Canvas), you would use anchors, pivots, and potentially scaling components (like Canvas Scaler UI Scale Mode) to ensure the UI adapts correctly to different screen sizes and aspect ratios. * **Origin Point:** Assume the (0, 0) coordinate is the **bottom-left** corner of the screen, common in some UI systems, or **top-left** (common in others - I will specify based on typical Unity Canvas usage: **(0,0) is Bottom-Left, (1080, 1920) is Top-Right** unless stated otherwise). Positions usually refer to the object's **pivot point** (often the center, unless specified). * **Font Sizes:** Pixel sizes for fonts are approximate and depend heavily on the specific font file used. * **Actors:** Actors like Cues and Effects have positions that change dynamically or are instantiated at specific world/UI coordinates. --- **A. Start Screen (1080x1920)** * **Widget:** `Title Text` (e.g., "RHYTHM CHEF: BEAT BITES") * **Position (Pivot: Center):** (540, 1600) `(Center X, ~83% Height)` * **Dimensions:** Auto-sized by text, constrained if needed. * **Font Size:** 90px * **Anchor Preset (Unity):** Top-Center * **Widget:** `Subtitle Text` (e.g., "(Core Demo)") * **Position (Pivot: Center):** (540, 1480) `(Center X, below Title)` * **Dimensions:** Auto-sized by text. * **Font Size:** 40px * **Anchor Preset (Unity):** Top-Center * **Widget:** `Start Button` * **Position (Pivot: Center):** (540, 400) `(Center X, ~21% Height)` * **Dimensions:** 450px (Width) x 150px (Height) * **Anchor Preset (Unity):** Bottom-Center * **Widget:** `Start Button Text` (e.g., "[ START ]") * **Position:** Centered within the Start Button. * **Font Size:** 60px --- **B. Gameplay Screen (1080x1920)** * **Widget:** `Score Text Label` (e.g., "SCORE:") * **Position (Pivot: Top-Left):** (40, 1880) `(Padding Left, Padding Top)` * **Dimensions:** Auto-sized by text. * **Font Size:** 50px * **Anchor Preset (Unity):** Top-Left * **Widget:** `Score Value Text` (e.g., "000") * **Position (Pivot: Top-Left):** (200, 1880) `(Right of Label, Same Top)` * **Dimensions:** Auto-sized by text (allow space for growth). * **Font Size:** 50px * **Anchor Preset (Unity):** Top-Left * **Widget:** `Combo Text Label` (e.g., "COMBO:") * **Position (Pivot: Top-Right):** (900, 1880) `(Approx position, adjust based on Value width)` * **Dimensions:** Auto-sized by text. * **Font Size:** 50px * **Anchor Preset (Unity):** Top-Right * **Widget:** `Combo Value Text` (e.g., "0x") * **Position (Pivot: Top-Right):** (1040, 1880) `(Padding Right, Same Top)` * **Dimensions:** Auto-sized by text (allow space for growth). * **Font Size:** 50px * **Anchor Preset (Unity):** Top-Right * **Area:** `Cue Travel Area` (Logical, no visual widget) * **Bounds:** Approx X = Center (e.g., 540), Y from 1800 (Spawn) down to ~200 (Despawn below target). * **Widget:** `Target Zone Visual` (The horizontal bar indicator) * **Position (Pivot: Center):** (540, 400) `(Center X, Defined Y)` * **Dimensions:** 900px (Width) x 80px (Height) * **Anchor Preset (Unity):** Position manually or Bottom-Center with Y offset. * **Note:** The *logical* hit detection center Y might be exactly 400. The timing windows (`perfectWindow`, `okWindow`) define the tolerance around this point in *time*, not necessarily pixels vertically (though they are related via cue speed). * **Actor:** `Cue Object` (Visual representation) * **Position:** Dynamic. Spawns near Y=1800, travels downwards to Y=400 (target). X is typically centered (540). * **Dimensions:** 80px (Width) x 80px (Height) (Example, adjust for visual clarity) * **Widget:** `Feedback Text` (e.g., "Perfect!", "Miss!") * **Position (Pivot: Center):** (540, 600) `(Center X, Above Target Zone)` * **Dimensions:** Auto-sized by text. * **Font Size:** 70px * **Anchor Preset (Unity):** Position manually or relative to Target Zone. (Appears temporarily). * **Actor:** `Hit/Miss Feedback Effect` (Particles/Animation) * **Position:** Instantiated at the Cue's position *when* the hit/miss occurs (approx X=540, Y=400). * **Dimensions:** Dynamic based on the effect design (e.g., expands to 150x150px briefly). --- **C. End Screen (1080x1920)** * **Widget:** `Completion Text` (e.g., "SEQUENCE COMPLETE!") * **Position (Pivot: Center):** (540, 1200) `(Center X, ~62% Height)` * **Dimensions:** Auto-sized by text. * **Font Size:** 70px * **Anchor Preset (Unity):** Center * **Widget:** `Final Score Text` (Optional, e.g., "Final Score: 025") * **Position (Pivot: Center):** (540, 1050) `(Center X, below Completion text)` * **Dimensions:** Auto-sized by text. * **Font Size:** 50px * **Anchor Preset (Unity):** Center * **Widget:** `Restart Button` * **Position (Pivot: Center):** (540, 400) `(Center X, ~21% Height - same as Start Button)` * **Dimensions:** 450px (Width) x 150px (Height) * **Anchor Preset (Unity):** Bottom-Center * **Widget:** `Restart Button Text` (e.g., "[ RESTART ]") * **Position:** Centered within the Restart Button. * **Font Size:** 60px --- Remember to implement proper UI scaling and anchoring in your chosen game engine to handle various device resolutions effectively beyond this 1080x1920 reference.
2
- Make the look and feel 100 times better, employ procedural graphics and emojis as sprites.
 
 
1
  Okay, here is a detailed, implementation-grade plan for building an interactive demonstrator for the core game mechanics of **Rhythm Chef: Beat Bites**. This focuses on creating a minimal viable product (MVP) specifically for user feedback on the core rhythm interaction feel, keeping the codebase limited. **Assumptions:** * **Engine:** Unity (common choice for hypercasual, good for rapid prototyping). * **Language:** C#. * **Target Platform:** Android (easy for distributing APKs for testing). * **Input Focus:** Start with **Tap** only for simplicity. Hold/Swipe can be added later if the Tap feels good. **I. Demonstrator Objectives** 1. Implement the core rhythm interaction: spawning cues, moving cues, detecting timed player input within a target zone. 2. Provide immediate, clear visual and audio feedback for successful hits and misses. 3. Synchronize cue movement and required input timing to a consistent beat (can be a simple metronome track or internal timer). 4. Allow a user to play through a short, predefined sequence of cues. 5. Keep the scope strictly limited to the core mechanic loop for fast iteration and focused feedback. **II. Scope Definition** * **IN SCOPE:** * Single, non-scrolling conveyor belt or lane for cues. * One type of cue requiring a **Tap** input. * One clearly defined target zone. * Precise timing mechanism for cue spawning and hit detection. * Simple visual representation of cues (e.g., colored circles/squares representing ingredients/actions). * Visual feedback (e.g., color change, simple particle effect, text popup like "Perfect!"/"Miss!"). * Basic audio feedback (hit sound, miss sound, beat/metronome sound). * A predefined, short sequence (~15-30 seconds) of Tap cues. * Minimal UI: Start Button, potentially a simple score/combo counter (optional but helpful). * **OUT OF SCOPE:** * Multiple lanes or complex patterns. * Hold or Swipe input types. * Multiple cue types/actions (chop, fry, etc.). * Any meta-game (restaurant, currency, upgrades). * Scoring beyond basic hit/miss feedback (no stars, complex calculations). * Multiple songs or difficulty levels. * Polished art assets (use placeholders). * Advanced UI, menus, settings. * Saving/loading progress. * Performance optimization beyond basic functionality. **III. Key Components & Implementation Details** 1. **`GameManager.cs`** * **Purpose:** Controls the overall state, timing, and sequence playback. * **Properties:** * `float bpm`: Beats per minute for the rhythm. * `float cueSpeed`: Speed at which cues travel towards the target. * `float targetZonePosition`: Y-coordinate (or X if horizontal) of the target zone center. * `float spawnPosition`: Y-coordinate (or X) where cues appear. * `GameObject cuePrefab`: Prefab for the visual cue object. * `Transform cueSpawnPoint`: Transform where cues are instantiated. * `AudioSource metronomeSource`: Optional, for playing a beat sound. * `List<CueData> sequence`: Holds the predefined sequence of cues (timing). * `float songStartTime`: Time when the sequence began (using `AudioSettings.dspTime` or `Time.timeSinceLevelLoad`). * `int currentSequenceIndex`: Tracks the next cue to spawn. * `bool isPlaying`: Game state flag. * **Methods:** * `StartSequence()`: Initializes timing, resets index, sets `isPlaying = true`. Starts metronome if used. * `Update()`: * If `isPlaying`, check `sequence` if it's time to spawn the `currentSequenceIndex` cue based on `bpm` and `songStartTime`. * If spawning, instantiate `cuePrefab` at `cueSpawnPoint`, calculate its `targetTime` (arrival time at target zone), and pass necessary data to the cue's script. Increment `currentSequenceIndex`. * Handles end of sequence. * `StopSequence()`: Sets `isPlaying = false`. 2. **`CueData.cs` (or Struct)** * **Purpose:** Simple data structure to define a single cue in the sequence. * **Properties:** * `float beatTimestamp`: The beat number (e.g., 1, 1.5, 2) within the sequence when this cue should *hit* the target zone. * `CueType type`: Enum (e.g., `Tap`). (Initially only Tap needed). 3. **`CueObject.cs` (attached to `cuePrefab`)** * **Purpose:** Represents a single moving cue. * **Properties:** * `float speed`: Movement speed (set by `GameManager`). * `float targetTime`: The exact game time (`Time.timeSinceLevelLoad` or `dspTime`) this cue should ideally be hit. * `bool isHit`: Flag to prevent multiple hits. * `bool canBeHit`: Flag to indicate if it's currently within the hittable window around the target zone. * **Methods:** * `Initialize(float targetTime, float speed)`: Called by `GameManager` on spawn. * `Update()`: * Move the cue downwards (or towards the target) at `speed * Time.deltaTime`. * Check if the cue has passed the target zone *without* being hit and *after* its hittable window - trigger a Miss condition if so and destroy/disable self. * `OnTriggerEnter/Exit2D(Collider2D other)`: If using physics triggers for the target zone, set `canBeHit = true/false`. * `ProcessHit()`: Called by `InputHandler` when a hit is registered on this cue. Sets `isHit = true`, triggers success feedback, potentially disables the cue visually, and schedules destruction. 4. **`TargetZone.cs` (attached to a GameObject with a Collider2D)** * **Purpose:** Defines the area where input is registered and cues are evaluated. * **Properties:** * `float perfectWindow`: Time window (+/- seconds) for a perfect hit. * `float okWindow`: Time window (+/- seconds) for an acceptable (non-miss) hit. (Keep simple first: just Perfect/Miss). * **Methods:** * `OnTriggerEnter2D/Exit2D(Collider2D other)`: Detects `CueObject` entering/leaving the zone's collider. Could be used by `CueObject` to set its `canBeHit` flag. * **Note:** Hit timing validation logic might live more centrally in `InputHandler` or `GameManager` rather than distributed here. 5. **`InputHandler.cs`** * **Purpose:** Detects player input and checks if it corresponds to a hittable cue. * **Properties:** * `TargetZone targetZone`: Reference to the target zone script/object. * `LayerMask cueLayer`: Physics layer for cues. * **Methods:** * `Update()`: * Check for Tap input (`Input.GetMouseButtonDown(0)` or `Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began`). * If Tap detected: * Determine the current game time (`Time.timeSinceLevelLoad` or `AudioSettings.dspTime`). * Find the "closest" active `CueObject` that is currently `canBeHit` (e.g., using Physics2D overlap checks near the target zone, or iterating through active cues and checking position/timing). * If a potential cue is found: * Calculate `timeDifference = currentTime - cue.targetTime`. * If `Mathf.Abs(timeDifference) <= targetZone.perfectWindow`: * Call `cue.ProcessHit()`. * Trigger "Perfect" feedback via `FeedbackManager`. * Else (if outside window but maybe an OK window exists later): * Trigger "Miss" feedback via `FeedbackManager` (or OK if implementing). * Potentially destroy/disable the cue to prevent late hits. * Else (no cue was hittable): * Optional: Trigger a generic "Miss" feedback for tapping empty space. 6. **`FeedbackManager.cs` (Singleton or easily accessible)** * **Purpose:** Centralized handler for triggering visual/audio feedback. * **Properties:** * `GameObject perfectHitEffectPrefab`: Particle effect/animation for perfect hits. * `GameObject missEffectPrefab`: Effect for misses. * `AudioClip hitSound`: Sound for successful hit. * `AudioClip missSound`: Sound for miss/error. * `AudioSource feedbackAudioSource`: Source to play feedback sounds. * `TextMeshProUGUI feedbackText`: UI Text element to display "Perfect!"/"Miss!". * **Methods:** * `ShowHitFeedback(Vector3 position)`: Instantiate `perfectHitEffectPrefab` at `position`, play `hitSound`, show "Perfect!" text briefly. * `ShowMissFeedback(Vector3 position)`: Instantiate `missEffectPrefab` at `position`, play `missSound`, show "Miss!" text briefly. **IV. Timing Implementation (CRITICAL)** * **Consistency is Key:** Use a consistent time source. * **Option A (Simpler):** `Time.timeSinceLevelLoad`. Easier for basic logic but can drift slightly from audio. Good enough for a demonstrator. * **Option B (More Accurate):** `AudioSettings.dspTime`. Provides highly accurate timing synced with the audio engine. Requires careful handling, especially when scheduling future events based on audio playback. * **Calculations:** * Convert `bpm` to seconds per beat (`60f / bpm`). * Calculate cue `targetTime`: `songStartTime + cue.beatTimestamp * secondsPerBeat`. * Calculate spawn time: `targetTime - travelDuration`, where `travelDuration` is `distance / cueSpeed`. Spawn the cue at this calculated spawn time. **V. UI Implementation (Minimal)** * Canvas with: * `Button` to call `GameManager.StartSequence()`. * `TextMeshProUGUI` (optional) for Score/Combo (incremented in `FeedbackManager` on hit, reset on miss). * `TextMeshProUGUI` for "Perfect!"/"Miss!" feedback text (controlled by `FeedbackManager`). **VI. Placeholder Assets** * **Cue:** Simple white Circle or Square sprite. * **Target Zone:** Semi-transparent rectangle/line across the lane. * **Hit Effect:** Simple particle burst (e.g., Unity's default particle system emitting a few sparks) or a quick scaling/fading circle. * **Miss Effect:** Red flash or different particle effect. * **Audio:** * Metronome: Simple "tick" sound. * Hit Sound: Short, satisfying "click" or "pop". * Miss Sound: Dull "thud" or "buzz". **VII. Build & Test Plan** 1. Implement core components (`GameManager`, `CueObject`, `InputHandler`, `TargetZone`, `FeedbackManager`). 2. Define a simple `sequence` in `GameManager` (e.g., 10 taps on consecutive beats). 3. Use precise timing based on `Time.timeSinceLevelLoad` initially. 4. Integrate basic visual and audio feedback. 5. Test internally: Does it *feel* responsive? Is the timing right? 6. Refine timing windows (`perfectWindow`) based on feel. 7. Build an Android APK. 8. Distribute APK to testers. 9. Gather feedback specifically on: * Timing sensitivity (too strict, too lenient?). * Clarity of visual cues. * Effectiveness of feedback (did they know if they hit/missed?). * Overall satisfaction/fun of the core interaction. **VIII. Success Criteria for Demonstrator** * The demonstrator runs smoothly on a target Android device. * Cues spawn and travel predictably, synchronized with the beat. * User taps near the target zone trigger immediate hit/miss feedback. * Feedback (visual and audio) is clear and correctly corresponds to input timing accuracy. * Testers can understand the core mechanic and provide feedback on its "feel" within 5 minutes of playing. * The codebase is minimal and focused solely on the described scope. Okay, here's an ASCII art representation of the UI and user flow for the **Rhythm Chef: Beat Bites** core mechanics demonstrator. **1. User Flow Diagram** ```ascii +-------------------+ +----------------------+ +----------------------+ | Start Screen | ---+->| Gameplay Loop |---+->| End Screen (Simple)| | (Title, [Start]) | User | (Cues, Target, Input)| User | (Score?, [Restart])| +-------------------+ Taps | | Finishes Sequence +----------------------+ Start +--<-------------------+ Or Fails | (Optional) | | | | Back to Start Screen | +----------------------+ +----------------------+ ``` **2. UI Mockups (ASCII Art)** **A. Start Screen** ```ascii +-----------------------------------------+ | | | // RHYTHM CHEF: BEAT BITES // | | (Core Demo) | | | | | | | | | | +-----------+ | | | [ START ]| | | +-----------+ | | | | | +-----------------------------------------+ User taps [ START ] --> Transitions to Gameplay Screen ``` **B. Gameplay Screen (Mid-Sequence)** * Imagine cues `(*)` moving downwards `v` towards the `TARGET ZONE`. * The player needs to tap when a cue is inside the `TARGET ZONE`. ```ascii +-----------------------------------------+ | SCORE: 005 COMBO: 3x | <--- Optional Score/Combo Display |-----------------------------------------| | | | | | (*) | <--- Incoming Cue 1 | v | | | | | | (*) | <--- Incoming Cue 2 | v | | | | ===================================== | \ | | TARGET ZONE | | <--- The Area to Tap In | ===================================== | / | v | | (*) | <--- Cue that just passed (or was missed) | | | | | | |-----------------------------------------| | FEEDBACK: | <--- Area for text feedback +-----------------------------------------+ ``` **C. Gameplay Screen (Moment of Tap - Perfect Hit)** * Player taps as `(*)` enters the `TARGET ZONE`. * Visual & text feedback appears. ```ascii +-----------------------------------------+ | SCORE: 006 COMBO: 4x | <--- Score/Combo Updated |-----------------------------------------| | | | | | (*) | | v | | | | | | (*) | | v | | | | ===================================== | | | > > > PERFECT! < < < | | <--- Cue hit inside, feedback shown | ===================================== | | | | | (Effect) | <--- Visual effect (e.g., ASCII explosion *`*`) | | | | |-----------------------------------------| | FEEDBACK: Perfect! | <--- Text feedback updated +-----------------------------------------+ ``` **D. Gameplay Screen (Moment of Tap - Miss)** * Player taps too early/late, or misses a cue. ```ascii +-----------------------------------------+ | SCORE: 006 COMBO: 0x | <--- Combo Reset |-----------------------------------------| | | | | | (*) | | v | | | | | | (*) | | v | | | | ===================================== | | | TARGET ZONE | | | ===================================== | | v | | (X) | <--- Missed cue indication / effect | | | | |-----------------------------------------| | FEEDBACK: Miss! | <--- Text feedback updated +-----------------------------------------+ ``` **E. End Screen (Simple Demo End)** * Appears after the predefined sequence finishes. ```ascii +-----------------------------------------+ | | | SEQUENCE COMPLETE! | | | | (Final Score: 025) | <--- Optional final score | | | | | +-------------+ | | | [ RESTART ] | | | +-------------+ | | | | | +-----------------------------------------+ User taps [ RESTART ] --> Transitions back to Gameplay Screen (restarts sequence) (Or could go back to the Start Screen) ``` This ASCII representation outlines the essential visual elements and the flow between them for the core mechanics demonstrator, focusing on clarity for user feedback on the rhythm interaction. Okay, here are specific pixel-based dimensions and positions for the UI elements based on a **reference screen resolution of 1080x1920 pixels (Width x Height - Portrait Orientation)**. **Important Considerations:** * **Reference Only:** These are *fixed pixel values* for the specified reference resolution. In a real implementation (e.g., using Unity Canvas), you would use anchors, pivots, and potentially scaling components (like Canvas Scaler UI Scale Mode) to ensure the UI adapts correctly to different screen sizes and aspect ratios. * **Origin Point:** Assume the (0, 0) coordinate is the **bottom-left** corner of the screen, common in some UI systems, or **top-left** (common in others - I will specify based on typical Unity Canvas usage: **(0,0) is Bottom-Left, (1080, 1920) is Top-Right** unless stated otherwise). Positions usually refer to the object's **pivot point** (often the center, unless specified). * **Font Sizes:** Pixel sizes for fonts are approximate and depend heavily on the specific font file used. * **Actors:** Actors like Cues and Effects have positions that change dynamically or are instantiated at specific world/UI coordinates. --- **A. Start Screen (1080x1920)** * **Widget:** `Title Text` (e.g., "RHYTHM CHEF: BEAT BITES") * **Position (Pivot: Center):** (540, 1600) `(Center X, ~83% Height)` * **Dimensions:** Auto-sized by text, constrained if needed. * **Font Size:** 90px * **Anchor Preset (Unity):** Top-Center * **Widget:** `Subtitle Text` (e.g., "(Core Demo)") * **Position (Pivot: Center):** (540, 1480) `(Center X, below Title)` * **Dimensions:** Auto-sized by text. * **Font Size:** 40px * **Anchor Preset (Unity):** Top-Center * **Widget:** `Start Button` * **Position (Pivot: Center):** (540, 400) `(Center X, ~21% Height)` * **Dimensions:** 450px (Width) x 150px (Height) * **Anchor Preset (Unity):** Bottom-Center * **Widget:** `Start Button Text` (e.g., "[ START ]") * **Position:** Centered within the Start Button. * **Font Size:** 60px --- **B. Gameplay Screen (1080x1920)** * **Widget:** `Score Text Label` (e.g., "SCORE:") * **Position (Pivot: Top-Left):** (40, 1880) `(Padding Left, Padding Top)` * **Dimensions:** Auto-sized by text. * **Font Size:** 50px * **Anchor Preset (Unity):** Top-Left * **Widget:** `Score Value Text` (e.g., "000") * **Position (Pivot: Top-Left):** (200, 1880) `(Right of Label, Same Top)` * **Dimensions:** Auto-sized by text (allow space for growth). * **Font Size:** 50px * **Anchor Preset (Unity):** Top-Left * **Widget:** `Combo Text Label` (e.g., "COMBO:") * **Position (Pivot: Top-Right):** (900, 1880) `(Approx position, adjust based on Value width)` * **Dimensions:** Auto-sized by text. * **Font Size:** 50px * **Anchor Preset (Unity):** Top-Right * **Widget:** `Combo Value Text` (e.g., "0x") * **Position (Pivot: Top-Right):** (1040, 1880) `(Padding Right, Same Top)` * **Dimensions:** Auto-sized by text (allow space for growth). * **Font Size:** 50px * **Anchor Preset (Unity):** Top-Right * **Area:** `Cue Travel Area` (Logical, no visual widget) * **Bounds:** Approx X = Center (e.g., 540), Y from 1800 (Spawn) down to ~200 (Despawn below target). * **Widget:** `Target Zone Visual` (The horizontal bar indicator) * **Position (Pivot: Center):** (540, 400) `(Center X, Defined Y)` * **Dimensions:** 900px (Width) x 80px (Height) * **Anchor Preset (Unity):** Position manually or Bottom-Center with Y offset. * **Note:** The *logical* hit detection center Y might be exactly 400. The timing windows (`perfectWindow`, `okWindow`) define the tolerance around this point in *time*, not necessarily pixels vertically (though they are related via cue speed). * **Actor:** `Cue Object` (Visual representation) * **Position:** Dynamic. Spawns near Y=1800, travels downwards to Y=400 (target). X is typically centered (540). * **Dimensions:** 80px (Width) x 80px (Height) (Example, adjust for visual clarity) * **Widget:** `Feedback Text` (e.g., "Perfect!", "Miss!") * **Position (Pivot: Center):** (540, 600) `(Center X, Above Target Zone)` * **Dimensions:** Auto-sized by text. * **Font Size:** 70px * **Anchor Preset (Unity):** Position manually or relative to Target Zone. (Appears temporarily). * **Actor:** `Hit/Miss Feedback Effect` (Particles/Animation) * **Position:** Instantiated at the Cue's position *when* the hit/miss occurs (approx X=540, Y=400). * **Dimensions:** Dynamic based on the effect design (e.g., expands to 150x150px briefly). --- **C. End Screen (1080x1920)** * **Widget:** `Completion Text` (e.g., "SEQUENCE COMPLETE!") * **Position (Pivot: Center):** (540, 1200) `(Center X, ~62% Height)` * **Dimensions:** Auto-sized by text. * **Font Size:** 70px * **Anchor Preset (Unity):** Center * **Widget:** `Final Score Text` (Optional, e.g., "Final Score: 025") * **Position (Pivot: Center):** (540, 1050) `(Center X, below Completion text)` * **Dimensions:** Auto-sized by text. * **Font Size:** 50px * **Anchor Preset (Unity):** Center * **Widget:** `Restart Button` * **Position (Pivot: Center):** (540, 400) `(Center X, ~21% Height - same as Start Button)` * **Dimensions:** 450px (Width) x 150px (Height) * **Anchor Preset (Unity):** Bottom-Center * **Widget:** `Restart Button Text` (e.g., "[ RESTART ]") * **Position:** Centered within the Restart Button. * **Font Size:** 60px --- Remember to implement proper UI scaling and anchoring in your chosen game engine to handle various device resolutions effectively beyond this 1080x1920 reference.
2
+ Make the look and feel 100 times better, employ procedural graphics and emojis as sprites.
3
+ Act as graphical effect engineer and add many more cool effect to the game play, make it explode with cool effects, particles etc., background effect ...