Upload index.html
Browse files- index.html +16 -8
index.html
CHANGED
|
@@ -2,6 +2,7 @@
|
|
| 2 |
<html lang="en">
|
| 3 |
<head>
|
| 4 |
<meta charset="utf-8"/>
|
|
|
|
| 5 |
<title>Lava Lamp</title>
|
| 6 |
<style>
|
| 7 |
html,body{margin:0;height:100%;background:#05030a;display:flex;align-items:center;justify-content:center;overflow:hidden}
|
|
@@ -9,7 +10,7 @@
|
|
| 9 |
</style>
|
| 10 |
</head>
|
| 11 |
<body>
|
| 12 |
-
<canvas id="c"></canvas>
|
| 13 |
<script>
|
| 14 |
"use strict";
|
| 15 |
// polyfill for older browsers (ctx.roundRect) so the lamp never crashes
|
|
@@ -97,10 +98,17 @@ canvas.addEventListener('pointermove',e=>{const p=canvasXY(e);ledHover=overLED(p
|
|
| 97 |
const endSlDrag=e=>{if(slDrag){slDrag=false;try{canvas.releasePointerCapture(e.pointerId);}catch(_){}}};
|
| 98 |
canvas.addEventListener('pointerup',endSlDrag);
|
| 99 |
canvas.addEventListener('pointercancel',endSlDrag);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
|
| 101 |
// ---- clickable LED: toggles a slow RGB colour cycle on the whole lamp ----
|
| 102 |
let RGB_MODE=false,rgbMix=0,hue=140; // mix eases 0(default) <-> 1(full RGB)
|
| 103 |
-
const
|
|
|
|
| 104 |
const DEF_L={r:255,g:90,b:45}; // the lamp's original warm colour
|
| 105 |
const LED_POS={x:CX,y:H-52};
|
| 106 |
let ledHover=false;
|
|
@@ -119,7 +127,7 @@ let LIGHT={...DEF_L},LUM_L=1; // effective lamp colour, updated ea
|
|
| 119 |
|
| 120 |
// ---- physics (px units) ----
|
| 121 |
let time=0,last=performance.now();
|
| 122 |
-
const SIM_SPEED=0.55;
|
| 123 |
const easeIO=t=>t<0.5?4*t*t*t:1-Math.pow(-2*t+2,3)/2;
|
| 124 |
const lerp=(a,b,t)=>a+(b-a)*t;
|
| 125 |
const ABS_DUR=1.6,BUD_DUR=2.6; // merge/split transition durations (s)
|
|
@@ -429,11 +437,11 @@ function drawGlass(){
|
|
| 429 |
refl.addColorStop(1,'rgba(255,255,255,0)');
|
| 430 |
ctx.fillStyle=refl;
|
| 431 |
ctx.beginPath();
|
| 432 |
-
// curved highlight on the left side
|
| 433 |
-
ctx.moveTo(CX-MAX_HW*0.
|
| 434 |
-
ctx.quadraticCurveTo(CX-MAX_HW*0.
|
| 435 |
-
ctx.lineTo(CX-MAX_HW*0.
|
| 436 |
-
ctx.quadraticCurveTo(CX-MAX_HW*0.
|
| 437 |
ctx.closePath();
|
| 438 |
ctx.fill();
|
| 439 |
// subtle right-side reflection
|
|
|
|
| 2 |
<html lang="en">
|
| 3 |
<head>
|
| 4 |
<meta charset="utf-8"/>
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
| 6 |
<title>Lava Lamp</title>
|
| 7 |
<style>
|
| 8 |
html,body{margin:0;height:100%;background:#05030a;display:flex;align-items:center;justify-content:center;overflow:hidden}
|
|
|
|
| 10 |
</style>
|
| 11 |
</head>
|
| 12 |
<body>
|
| 13 |
+
<canvas id="c" tabindex="0" aria-label="Animated lava lamp. Press space to toggle colour mode; use left and right arrow keys to adjust the wax amount."></canvas>
|
| 14 |
<script>
|
| 15 |
"use strict";
|
| 16 |
// polyfill for older browsers (ctx.roundRect) so the lamp never crashes
|
|
|
|
| 98 |
const endSlDrag=e=>{if(slDrag){slDrag=false;try{canvas.releasePointerCapture(e.pointerId);}catch(_){}}};
|
| 99 |
canvas.addEventListener('pointerup',endSlDrag);
|
| 100 |
canvas.addEventListener('pointercancel',endSlDrag);
|
| 101 |
+
// keyboard: space/enter toggles the light, arrows adjust wax (same maths as dragging)
|
| 102 |
+
canvas.addEventListener('keydown',e=>{
|
| 103 |
+
if(e.code==='Space'||e.code==='Enter'){RGB_MODE=!RGB_MODE;e.preventDefault();}
|
| 104 |
+
else if(e.code==='ArrowRight'||e.code==='ArrowUp'){setWaxFromX(SL.x-SL.w/2+Math.min(1,slF+0.06)*SL.w);e.preventDefault();}
|
| 105 |
+
else if(e.code==='ArrowLeft'||e.code==='ArrowDown'){setWaxFromX(SL.x-SL.w/2+Math.max(0,slF-0.06)*SL.w);e.preventDefault();}
|
| 106 |
+
});
|
| 107 |
|
| 108 |
// ---- clickable LED: toggles a slow RGB colour cycle on the whole lamp ----
|
| 109 |
let RGB_MODE=false,rgbMix=0,hue=140; // mix eases 0(default) <-> 1(full RGB)
|
| 110 |
+
const RM=matchMedia('(prefers-reduced-motion: reduce)').matches; // respect OS motion setting
|
| 111 |
+
const HUE_SPEED=(360/16)*(RM?0.5:1); // one full colour cycle every ~16 s (slower for reduced motion)
|
| 112 |
const DEF_L={r:255,g:90,b:45}; // the lamp's original warm colour
|
| 113 |
const LED_POS={x:CX,y:H-52};
|
| 114 |
let ledHover=false;
|
|
|
|
| 127 |
|
| 128 |
// ---- physics (px units) ----
|
| 129 |
let time=0,last=performance.now();
|
| 130 |
+
const SIM_SPEED=0.55*(RM?0.5:1); // slow, heavy wax (scales all motion + transitions)
|
| 131 |
const easeIO=t=>t<0.5?4*t*t*t:1-Math.pow(-2*t+2,3)/2;
|
| 132 |
const lerp=(a,b,t)=>a+(b-a)*t;
|
| 133 |
const ABS_DUR=1.6,BUD_DUR=2.6; // merge/split transition durations (s)
|
|
|
|
| 437 |
refl.addColorStop(1,'rgba(255,255,255,0)');
|
| 438 |
ctx.fillStyle=refl;
|
| 439 |
ctx.beginPath();
|
| 440 |
+
// curved highlight on the left side (flipped: now faces left "(" with a touch more curve)
|
| 441 |
+
ctx.moveTo(CX-MAX_HW*0.35,LIQ_TOP+20);
|
| 442 |
+
ctx.quadraticCurveTo(CX-MAX_HW*0.60,(LIQ_TOP+LIQ_BOT)/2,CX-MAX_HW*0.42,LIQ_BOT-30);
|
| 443 |
+
ctx.lineTo(CX-MAX_HW*0.65,LIQ_BOT-20);
|
| 444 |
+
ctx.quadraticCurveTo(CX-MAX_HW*0.80,(LIQ_TOP+LIQ_BOT)/2,CX-MAX_HW*0.58,LIQ_TOP+30);
|
| 445 |
ctx.closePath();
|
| 446 |
ctx.fill();
|
| 447 |
// subtle right-side reflection
|