|
1 | | -// Project Registry |
| 1 | +// Project Registry |
2 | 2 | // Each project's HTML and logic lives in its own file under js/projects/ |
3 | 3 |
|
4 | 4 |
|
@@ -60,281 +60,7 @@ function getProjectHTML(projectName) { |
60 | 60 | // ============================================ |
61 | 61 | // DICE ROLLING |
62 | 62 | // ============================================ |
63 | | -function getDiceRollingHTML() { |
64 | | - return ` |
65 | | - <div class="project-content"> |
66 | | - <h2>🎲 Dice Rolling</h2> |
67 | | - <div class="dice-container"> |
68 | | - <div class="dice-display"> |
69 | | - <div class="dice-scene"> |
70 | | - <div class="dice-cube" id="dice1"> |
71 | | - <div class="cube-face face-1"></div> |
72 | | - <div class="cube-face face-2"></div> |
73 | | - <div class="cube-face face-3"></div> |
74 | | - <div class="cube-face face-4"></div> |
75 | | - <div class="cube-face face-5"></div> |
76 | | - <div class="cube-face face-6"></div> |
77 | | - </div> |
78 | | - <div class="dice-shadow"></div> |
79 | | - </div> |
80 | | -
|
81 | | - <div class="dice-scene"> |
82 | | - <div class="dice-cube" id="dice2"> |
83 | | - <div class="cube-face face-1"></div> |
84 | | - <div class="cube-face face-2"></div> |
85 | | - <div class="cube-face face-3"></div> |
86 | | - <div class="cube-face face-4"></div> |
87 | | - <div class="cube-face face-5"></div> |
88 | | - <div class="cube-face face-6"></div> |
89 | | - </div> |
90 | | - <div class="dice-shadow"></div> |
91 | | - </div> |
92 | | - </div> |
93 | | - |
94 | | - <div class="dice-total"> |
95 | | - <span>Total: </span> |
96 | | - <span id="diceTotal">2</span> |
97 | | - </div> |
98 | | - |
99 | | - <button class="btn-roll" id="rollDice">🎲 Roll Dice</button> |
100 | | - </div> |
101 | | - </div> |
102 | | - |
103 | | - <style> |
104 | | - .dice-container { |
105 | | - text-align: center; |
106 | | - padding: 3rem 2rem; |
107 | | - } |
108 | | - |
109 | | - .dice-display { |
110 | | - display: flex; |
111 | | - gap: 2rem; |
112 | | - justify-content: center; |
113 | | - margin-bottom: 2rem; |
114 | | - flex-wrap: wrap; |
115 | | - } |
116 | | -
|
117 | | - .dice-scene { |
118 | | - position: relative; |
119 | | - width: 120px; |
120 | | - height: 150px; |
121 | | - perspective: 700px; |
122 | | - transform-origin: center bottom; |
123 | | - } |
124 | | - |
125 | | - .dice-cube { |
126 | | - --rx: 0deg; |
127 | | - --ry: 0deg; |
128 | | - width: 120px; |
129 | | - height: 120px; |
130 | | - position: relative; |
131 | | - transform-style: preserve-3d; |
132 | | - transform: rotateX(var(--rx)) rotateY(var(--ry)); |
133 | | - transition: transform 1.3s cubic-bezier(0.2, 0.75, 0.15, 1), filter 0.3s ease; |
134 | | - } |
135 | | -
|
136 | | - .dice-shadow { |
137 | | - position: absolute; |
138 | | - left: 50%; |
139 | | - bottom: 6px; |
140 | | - width: 78px; |
141 | | - height: 14px; |
142 | | - transform: translateX(-50%); |
143 | | - border-radius: 50%; |
144 | | - background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.35) 0%, rgba(0, 0, 0, 0.05) 70%, transparent 100%); |
145 | | - transition: opacity 0.3s ease; |
146 | | - } |
147 | | -
|
148 | | - .dice-scene.rolling .dice-shadow { |
149 | | - animation: diceShadowFloat 1.3s ease; |
150 | | - } |
151 | | -
|
152 | | - .dice-scene.impact { |
153 | | - animation: diceLanding 0.4s ease-out; |
154 | | - } |
155 | | -
|
156 | | - .dice-scene.impact .dice-shadow { |
157 | | - animation: diceShadowImpact 0.4s ease-out; |
158 | | - } |
159 | | - |
160 | | - .cube-face { |
161 | | - --size: 120px; |
162 | | - --dot: 14px; |
163 | | - position: absolute; |
164 | | - width: var(--size); |
165 | | - height: var(--size); |
166 | | - border-radius: 18px; |
167 | | - background: linear-gradient(160deg, #ffffff, #e6ebf2); |
168 | | - border: 2px solid #d8dee8; |
169 | | - box-shadow: inset -8px -8px 12px rgba(0, 0, 0, 0.08), inset 8px 8px 12px rgba(255, 255, 255, 0.85); |
170 | | - } |
171 | | -
|
172 | | - .cube-face::before { |
173 | | - content: ''; |
174 | | - position: absolute; |
175 | | - inset: 0; |
176 | | - border-radius: 18px; |
177 | | - background-repeat: no-repeat; |
178 | | - } |
179 | | -
|
180 | | - .face-1 { transform: translateZ(60px); } |
181 | | - .face-2 { transform: rotateY(90deg) translateZ(60px); } |
182 | | - .face-3 { transform: rotateY(180deg) translateZ(60px); } |
183 | | - .face-4 { transform: rotateY(-90deg) translateZ(60px); } |
184 | | - .face-5 { transform: rotateX(90deg) translateZ(60px); } |
185 | | - .face-6 { transform: rotateX(-90deg) translateZ(60px); } |
186 | | -
|
187 | | - .face-1::before { |
188 | | - background-image: radial-gradient(circle at 50% 50%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)); |
189 | | - } |
190 | | -
|
191 | | - .face-2::before { |
192 | | - background-image: |
193 | | - radial-gradient(circle at 28% 28%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)), |
194 | | - radial-gradient(circle at 72% 72%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)); |
195 | | - } |
196 | | -
|
197 | | - .face-3::before { |
198 | | - background-image: |
199 | | - radial-gradient(circle at 28% 28%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)), |
200 | | - radial-gradient(circle at 50% 50%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)), |
201 | | - radial-gradient(circle at 72% 72%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)); |
202 | | - } |
203 | | -
|
204 | | - .face-4::before { |
205 | | - background-image: |
206 | | - radial-gradient(circle at 28% 28%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)), |
207 | | - radial-gradient(circle at 72% 28%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)), |
208 | | - radial-gradient(circle at 28% 72%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)), |
209 | | - radial-gradient(circle at 72% 72%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)); |
210 | | - } |
211 | | -
|
212 | | - .face-5::before { |
213 | | - background-image: |
214 | | - radial-gradient(circle at 28% 28%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)), |
215 | | - radial-gradient(circle at 72% 28%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)), |
216 | | - radial-gradient(circle at 50% 50%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)), |
217 | | - radial-gradient(circle at 28% 72%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)), |
218 | | - radial-gradient(circle at 72% 72%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)); |
219 | | - } |
220 | | -
|
221 | | - .face-6::before { |
222 | | - background-image: |
223 | | - radial-gradient(circle at 28% 24%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)), |
224 | | - radial-gradient(circle at 72% 24%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)), |
225 | | - radial-gradient(circle at 28% 50%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)), |
226 | | - radial-gradient(circle at 72% 50%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)), |
227 | | - radial-gradient(circle at 28% 76%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)), |
228 | | - radial-gradient(circle at 72% 76%, #111 0 var(--dot), transparent calc(var(--dot) + 1px)); |
229 | | - } |
230 | | - |
231 | | - .dice-total { |
232 | | - font-size: 2rem; |
233 | | - margin: 2rem 0; |
234 | | - font-weight: bold; |
235 | | - } |
236 | | - |
237 | | - .btn-roll { |
238 | | - background: linear-gradient(135deg, #ff6b6b, #ee5a6f); |
239 | | - color: white; |
240 | | - border: none; |
241 | | - padding: 1rem 3rem; |
242 | | - border-radius: 50px; |
243 | | - font-size: 1.3rem; |
244 | | - cursor: pointer; |
245 | | - transition: var(--transition); |
246 | | - } |
247 | | - |
248 | | - .btn-roll:hover { |
249 | | - transform: scale(1.05); |
250 | | - box-shadow: 0 5px 20px rgba(255, 107, 107, 0.4); |
251 | | - } |
252 | | -
|
253 | | - @keyframes diceLanding { |
254 | | - 0% { transform: translateY(-10px); } |
255 | | - 55% { transform: translateY(4px); } |
256 | | - 80% { transform: translateY(-2px); } |
257 | | - 100% { transform: translateY(0); } |
258 | | - } |
259 | | -
|
260 | | - @keyframes diceShadowFloat { |
261 | | - 0%, 100% { transform: translateX(-50%) scale(1); opacity: 0.32; } |
262 | | - 45% { transform: translateX(-50%) scale(0.72); opacity: 0.2; } |
263 | | - } |
264 | | -
|
265 | | - @keyframes diceShadowImpact { |
266 | | - 0% { transform: translateX(-50%) scale(0.74); opacity: 0.2; } |
267 | | - 55% { transform: translateX(-50%) scale(1.08); opacity: 0.38; } |
268 | | - 100% { transform: translateX(-50%) scale(1); opacity: 0.32; } |
269 | | - } |
270 | | - </style> |
271 | | - `; |
272 | | -} |
273 | | - |
274 | | -function initDiceRolling() { |
275 | | - const dice1 = document.getElementById('dice1'); |
276 | | - const dice2 = document.getElementById('dice2'); |
277 | | - const diceScene1 = dice1.closest('.dice-scene'); |
278 | | - const diceScene2 = dice2.closest('.dice-scene'); |
279 | | - const rollBtn = document.getElementById('rollDice'); |
280 | | - const totalDisplay = document.getElementById('diceTotal'); |
281 | | - |
282 | | - const faceRotation = { |
283 | | - 1: { x: 0, y: 0 }, |
284 | | - 2: { x: 0, y: -90 }, |
285 | | - 3: { x: 0, y: 180 }, |
286 | | - 4: { x: 0, y: 90 }, |
287 | | - 5: { x: -90, y: 0 }, |
288 | | - 6: { x: 90, y: 0 } |
289 | | - }; |
290 | | - |
291 | | - let spins1 = 0; |
292 | | - let spins2 = 0; |
293 | | - |
294 | | - function setCubeFace(cube, value, spinSeed) { |
295 | | - const target = faceRotation[value]; |
296 | | - const rx = target.x + 360 * (2 + (spinSeed % 3)); |
297 | | - const ry = target.y + 360 * (3 + (spinSeed % 2)); |
298 | | - cube.style.setProperty('--rx', `${rx}deg`); |
299 | | - cube.style.setProperty('--ry', `${ry}deg`); |
300 | | - } |
301 | | - |
302 | | - function triggerLanding(scene) { |
303 | | - scene.classList.remove('impact'); |
304 | | - void scene.offsetWidth; |
305 | | - scene.classList.add('impact'); |
306 | | - setTimeout(() => { |
307 | | - scene.classList.remove('impact'); |
308 | | - }, 420); |
309 | | - } |
310 | | - |
311 | | - setCubeFace(dice1, 1, 0); |
312 | | - setCubeFace(dice2, 1, 1); |
313 | | - totalDisplay.textContent = '2'; |
314 | | - |
315 | | - rollBtn.addEventListener('click', () => { |
316 | | - rollBtn.disabled = true; |
317 | | - diceScene1.classList.add('rolling'); |
318 | | - diceScene2.classList.add('rolling'); |
319 | | - |
320 | | - const value1 = Math.floor(Math.random() * 6) + 1; |
321 | | - const value2 = Math.floor(Math.random() * 6) + 1; |
322 | | - spins1 += 1; |
323 | | - spins2 += 1; |
324 | | - |
325 | | - setCubeFace(dice1, value1, spins1); |
326 | | - setCubeFace(dice2, value2, spins2); |
327 | | - |
328 | | - setTimeout(() => { |
329 | | - diceScene1.classList.remove('rolling'); |
330 | | - diceScene2.classList.remove('rolling'); |
331 | | - triggerLanding(diceScene1); |
332 | | - triggerLanding(diceScene2); |
333 | | - totalDisplay.textContent = value1 + value2; |
334 | | - rollBtn.disabled = false; |
335 | | - }, 1300); |
336 | | - }); |
337 | | -} |
| 63 | +// Moved to js/projects/dice-rolling.js |
338 | 64 |
|
339 | 65 | // ============================================ |
340 | 66 | // COIN FLIP |
|
0 commit comments