Replace CSS floor with canvas perspective grid
Draws vertical lines radiating from a true central vanishing point and horizontal lines with perspective-correct spacing — giving the classic retrowave convergence effect instead of parallel lines viewed from above. Horizon glow line restored above the canvas layer. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
22d9f9672b
commit
5378772d8a
1 changed files with 74 additions and 43 deletions
|
|
@ -69,41 +69,11 @@ html, body {
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
RETROWAVE GRID FLOOR
|
RETROWAVE GRID FLOOR
|
||||||
============================================================ */
|
============================================================ */
|
||||||
.floor-wrap {
|
#floorCanvas {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0; left: 0; right: 0;
|
bottom: 0; left: 0;
|
||||||
height: 42%;
|
|
||||||
overflow: hidden;
|
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
.floor {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
left: -100%; right: -100%;
|
|
||||||
height: 400%;
|
|
||||||
transform: perspective(700px) rotateX(55deg);
|
|
||||||
transform-origin: bottom center;
|
|
||||||
background-image:
|
|
||||||
repeating-linear-gradient(
|
|
||||||
90deg,
|
|
||||||
transparent 0,
|
|
||||||
transparent calc(5% - 2px),
|
|
||||||
rgba(0, 200, 255, 0.3) calc(5% - 2px),
|
|
||||||
rgba(0, 200, 255, 0.3) 5%
|
|
||||||
),
|
|
||||||
repeating-linear-gradient(
|
|
||||||
0deg,
|
|
||||||
transparent 0,
|
|
||||||
transparent 48px,
|
|
||||||
rgba(0, 200, 255, 0.2) 48px,
|
|
||||||
rgba(0, 200, 255, 0.2) 50px
|
|
||||||
);
|
|
||||||
animation: gridScroll 0.833s linear infinite;
|
|
||||||
}
|
|
||||||
@keyframes gridScroll {
|
|
||||||
from { background-position: 0 0, 0 0; }
|
|
||||||
to { background-position: 0 0, 0 50px; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Horizon glow line */
|
/* Horizon glow line */
|
||||||
.horizon {
|
.horizon {
|
||||||
|
|
@ -716,14 +686,12 @@ html, body {
|
||||||
<!-- Twinkling starfield -->
|
<!-- Twinkling starfield -->
|
||||||
<canvas id="starfield"></canvas>
|
<canvas id="starfield"></canvas>
|
||||||
|
|
||||||
|
<!-- Retrowave grid floor -->
|
||||||
|
<canvas id="floorCanvas"></canvas>
|
||||||
|
|
||||||
<!-- Horizon glow -->
|
<!-- Horizon glow -->
|
||||||
<div class="horizon"></div>
|
<div class="horizon"></div>
|
||||||
|
|
||||||
<!-- Retrowave grid floor -->
|
|
||||||
<div class="floor-wrap">
|
|
||||||
<div class="floor"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- ===================== ROBOT ===================== -->
|
<!-- ===================== ROBOT ===================== -->
|
||||||
<div class="robot-wrap">
|
<div class="robot-wrap">
|
||||||
<div class="robot">
|
<div class="robot">
|
||||||
|
|
@ -878,13 +846,76 @@ window.addEventListener('resize', resizeCanvas);
|
||||||
resizeCanvas();
|
resizeCanvas();
|
||||||
requestAnimationFrame(drawStars);
|
requestAnimationFrame(drawStars);
|
||||||
|
|
||||||
const floorEl = document.querySelector('.floor');
|
/* ============================================================
|
||||||
function updateFloorPerspective() {
|
FLOOR CANVAS — perspective grid with true vanishing point
|
||||||
const p = Math.round(window.innerHeight * 1.05);
|
============================================================ */
|
||||||
floorEl.style.transform = `perspective(${p}px) rotateX(55deg)`;
|
const floorCanvas = document.getElementById('floorCanvas');
|
||||||
|
const floorCtx = floorCanvas.getContext('2d');
|
||||||
|
|
||||||
|
const FLOOR_RATIO = 0.42;
|
||||||
|
const V_LINES = 24;
|
||||||
|
const H_LINES = 24;
|
||||||
|
let floorScroll = 0;
|
||||||
|
let lastFloorTs = 0;
|
||||||
|
|
||||||
|
function resizeFloor() {
|
||||||
|
floorCanvas.width = window.innerWidth;
|
||||||
|
floorCanvas.height = Math.round(window.innerHeight * FLOOR_RATIO);
|
||||||
}
|
}
|
||||||
window.addEventListener('resize', updateFloorPerspective);
|
|
||||||
updateFloorPerspective();
|
function drawFloor(ts) {
|
||||||
|
const dt = lastFloorTs ? Math.min((ts - lastFloorTs) / 1000, 0.1) : 0;
|
||||||
|
lastFloorTs = ts;
|
||||||
|
floorScroll = (floorScroll + 0.06 * dt) % 1;
|
||||||
|
|
||||||
|
const W = floorCanvas.width;
|
||||||
|
const H = floorCanvas.height;
|
||||||
|
const vx = W / 2;
|
||||||
|
|
||||||
|
floorCtx.clearRect(0, 0, W, H);
|
||||||
|
|
||||||
|
// Vertical lines radiating from vanishing point (center top)
|
||||||
|
// Bottom spread exceeds screen width so laterals are filled
|
||||||
|
const spread = W * 4;
|
||||||
|
const spreadStart = vx - spread / 2;
|
||||||
|
floorCtx.strokeStyle = 'rgba(0, 200, 255, 0.32)';
|
||||||
|
floorCtx.lineWidth = 2;
|
||||||
|
for (let i = 0; i <= V_LINES; i++) {
|
||||||
|
const bx = spreadStart + (i / V_LINES) * spread;
|
||||||
|
floorCtx.beginPath();
|
||||||
|
floorCtx.moveTo(vx, 0);
|
||||||
|
floorCtx.lineTo(bx, H);
|
||||||
|
floorCtx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Horizontal lines — perspective-correct spacing, animated
|
||||||
|
for (let i = 0; i < H_LINES; i++) {
|
||||||
|
const t = ((i / H_LINES) + floorScroll) % 1;
|
||||||
|
const depth = Math.pow(t, 2.2); // power curve: compressed near horizon
|
||||||
|
const y = depth * H;
|
||||||
|
const x1 = vx - (spread / 2) * depth;
|
||||||
|
const x2 = vx + (spread / 2) * depth;
|
||||||
|
floorCtx.strokeStyle = `rgba(0, 200, 255, ${(0.12 + depth * 0.25).toFixed(2)})`;
|
||||||
|
floorCtx.lineWidth = Math.max(1, depth * 11);
|
||||||
|
floorCtx.beginPath();
|
||||||
|
floorCtx.moveTo(x1, y);
|
||||||
|
floorCtx.lineTo(x2, y);
|
||||||
|
floorCtx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fade near horizon to hide sub-pixel lines
|
||||||
|
const fade = floorCtx.createLinearGradient(0, 0, 0, H * 0.3);
|
||||||
|
fade.addColorStop(0, '#000814');
|
||||||
|
fade.addColorStop(1, 'rgba(0,8,20,0)');
|
||||||
|
floorCtx.fillStyle = fade;
|
||||||
|
floorCtx.fillRect(0, 0, W, H * 0.3);
|
||||||
|
|
||||||
|
requestAnimationFrame(drawFloor);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', resizeFloor);
|
||||||
|
resizeFloor();
|
||||||
|
requestAnimationFrame(drawFloor);
|
||||||
|
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue