Skip to content

Commit dcc5f92

Browse files
authored
hehe
1 parent fd488fc commit dcc5f92

1 file changed

Lines changed: 158 additions & 102 deletions

File tree

index.html

Lines changed: 158 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,134 +1,190 @@
11
<!DOCTYPE html>
2-
<html lang="en" class="scroll-smooth">
2+
<html lang="en">
33
<head>
4-
<meta charset="UTF-8" />
5-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6-
<title>Cyberfiction Style • PNG Scroll Sequence</title>
4+
<meta charset="UTF-8">
5+
<title>3D Scroll Scrub PNG Sequence</title>
76
<style>
8-
body {
7+
html, body {
98
margin: 0;
10-
background: #000;
11-
color: #fff;
12-
font-family: 'Inter', sans-serif;
13-
overflow-x: hidden;
14-
height: 600vh; /* enough scroll space for sequence */
9+
padding: 0;
10+
overflow: hidden;
11+
height: 100%;
12+
background: #fff;
1513
}
16-
header {
17-
position: relative;
18-
z-index: 2;
19-
text-align: center;
20-
padding: 4rem 1rem;
21-
}
22-
header h1 {
23-
font-size: 3rem;
24-
font-weight: 700;
25-
margin-bottom: 1rem;
26-
}
27-
header p {
28-
font-size: 1.25rem;
29-
color: #aaa;
30-
}
31-
#hero-sequence {
32-
position: fixed;
14+
canvas {
15+
display: block;
16+
margin: auto;
17+
position: absolute;
3318
top: 50%;
3419
left: 50%;
3520
transform: translate(-50%, -50%);
36-
z-index: 1;
37-
max-width: 80vw;
38-
max-height: 80vh;
39-
pointer-events: none;
40-
transition: transform 0.1s ease-out;
41-
opacity: 0; /* hidden until preloaded */
21+
image-rendering: crisp-edges;
22+
image-rendering: -webkit-optimize-contrast;
4223
}
43-
#loading {
24+
#help-overlay {
4425
position: fixed;
45-
top: 50%;
46-
left: 50%;
47-
transform: translate(-50%, -50%);
48-
color: #0ff;
49-
font-size: 1.5rem;
50-
font-family: monospace;
26+
top: 20px;
27+
right: 20px;
28+
background: rgba(0,0,0,0.8);
29+
color: white;
30+
padding: 16px 20px;
31+
border-radius: 12px;
32+
font-family: sans-serif;
33+
font-size: 14px;
34+
line-height: 1.6;
35+
max-width: 280px;
36+
z-index: 9999;
37+
opacity: 1;
38+
transition: opacity 0.6s ease;
39+
cursor: grab;
5140
}
52-
main {
53-
position: relative;
54-
z-index: 2;
55-
background: rgba(0,0,0,0.85);
56-
padding: 4rem 2rem;
57-
text-align: center;
41+
#help-overlay:active {
42+
cursor: grabbing;
5843
}
5944
</style>
6045
</head>
6146
<body>
62-
<header>
63-
<h1>Cyberfiction Inspired</h1>
64-
<p>Scroll down to rotate the 3D PNG sequence</p>
65-
</header>
66-
67-
<!-- Loading text -->
68-
<div id="loading">Loading 0%</div>
69-
70-
<!-- Image sequence -->
71-
<img id="hero-sequence" src="male0001.png" alt="3D Sequence Frame"/>
47+
<canvas id="sequence"></canvas>
7248

73-
<main>
74-
<h2>About</h2>
75-
<p>This demo scrubs through <code>male0001.png ... male0300.png</code>
76-
in the root folder based on your scroll position.</p>
77-
</main>
49+
<div id="help-overlay">
50+
<strong>Controls</strong><br>
51+
🖱️ Scroll / drag → rotate<br>
52+
👆 Tap → reset<br>
53+
👆👆 Double-tap → stop<br>
54+
✌️ Two-finger tap → last frame<br>
55+
🤏 Pinch → zoom<br><br>
56+
⬅️➡️ Arrows → rotate<br>
57+
␣ Space → stop<br>
58+
R → reset<br>
59+
L → last frame<br>
60+
+ / - → zoom<br>
61+
H → toggle help
62+
</div>
7863

7964
<script>
80-
const hero = document.getElementById('hero-sequence');
81-
const loading = document.getElementById('loading');
82-
83-
const totalFrames = 300; // you have 300 PNGs
84-
const frames = [];
65+
const canvas = document.getElementById("sequence");
66+
const ctx = canvas.getContext("2d");
67+
let width, height;
68+
function resizeCanvas() {
69+
width = window.innerWidth;
70+
height = window.innerHeight;
71+
canvas.width = width;
72+
canvas.height = height;
73+
}
74+
window.addEventListener("resize", resizeCanvas);
75+
resizeCanvas();
8576

86-
let targetRotX = 0, targetRotY = 0;
77+
const frameCount = 300;
78+
const images = [];
79+
let loaded = 0;
8780

88-
// Preload all images
89-
let loadedCount = 0;
90-
for (let i = 1; i <= totalFrames; i++) {
91-
const frameNumber = String(i).padStart(4, '0'); // male0001
81+
// Preload sequence
82+
for (let i = 1; i <= frameCount; i++) {
9283
const img = new Image();
93-
img.src = `male${frameNumber}.png`;
84+
img.src = `male${String(i).padStart(4,"0")}.png`;
9485
img.onload = () => {
95-
loadedCount++;
96-
const percent = Math.floor((loadedCount / totalFrames) * 100);
97-
loading.textContent = `Loading ${percent}%`;
98-
99-
if (loadedCount === totalFrames) {
100-
loading.style.display = "none";
101-
hero.style.opacity = 1;
102-
updateFrame();
103-
}
86+
loaded++;
87+
if (loaded === 1) drawFrame(1); // show first frame asap
10488
};
105-
frames.push(img);
89+
images.push(img);
10690
}
10791

108-
// Scroll controls frame
109-
function updateFrame() {
110-
const scrollTop = window.scrollY;
111-
const maxScroll = document.body.scrollHeight - window.innerHeight;
112-
const scrollFraction = scrollTop / maxScroll;
113-
const frameIndex = Math.min(
114-
totalFrames - 1,
115-
Math.floor(scrollFraction * totalFrames)
116-
);
117-
const frameNumber = String(frameIndex + 1).padStart(4, '0');
118-
hero.src = `male${frameNumber}.png`;
119-
requestAnimationFrame(updateFrame);
92+
let currentFrame = 1;
93+
let targetFrame = 1;
94+
let isPlaying = true;
95+
let scale = 1;
96+
let tiltX = 0, tiltY = 0;
97+
98+
function drawFrame(frame) {
99+
ctx.clearRect(0, 0, width, height);
100+
const img = images[frame - 1];
101+
if (!img.complete) return;
102+
const iw = img.width * scale;
103+
const ih = img.height * scale;
104+
const x = (width - iw) / 2 + tiltX * 30;
105+
const y = (height - ih) / 2 + tiltY * 30;
106+
ctx.drawImage(img, x, y, iw, ih);
107+
}
108+
109+
// Smooth animation loop
110+
function animate() {
111+
if (isPlaying) {
112+
currentFrame += (targetFrame - currentFrame) * 0.1;
113+
if (Math.abs(targetFrame - currentFrame) < 0.01) currentFrame = targetFrame;
114+
drawFrame(Math.round(currentFrame));
115+
}
116+
requestAnimationFrame(animate);
120117
}
118+
animate();
119+
120+
// --- Scroll & drag scrub ---
121+
let lastY = 0;
122+
window.addEventListener("wheel", (e) => {
123+
targetFrame += Math.sign(e.deltaY) * 3;
124+
targetFrame = Math.max(1, Math.min(frameCount, targetFrame));
125+
});
126+
window.addEventListener("mousedown", (e) => { lastY = e.clientY; });
127+
window.addEventListener("mousemove", (e) => {
128+
if (e.buttons) {
129+
let delta = e.clientY - lastY;
130+
targetFrame += delta > 0 ? 2 : -2;
131+
targetFrame = Math.max(1, Math.min(frameCount, targetFrame));
132+
lastY = e.clientY;
133+
}
134+
});
121135

122-
// Mouse interaction for tilt
123-
window.addEventListener('mousemove', (e) => {
124-
const x = (e.clientX / window.innerWidth) * 2 - 1;
125-
const y = (e.clientY / window.innerHeight) * 2 - 1;
126-
targetRotY = x * 10; // horizontal tilt
127-
targetRotX = y * 10; // vertical tilt
128-
hero.style.transform = `translate(-50%, -50%) rotateX(${targetRotX}deg) rotateY(${targetRotY}deg)`;
136+
// --- Tilt effect ---
137+
window.addEventListener("mousemove", (e) => {
138+
tiltX = (e.clientX / width - 0.5);
139+
tiltY = (e.clientY / height - 0.5);
129140
});
130141

131-
requestAnimationFrame(updateFrame);
142+
// --- Keyboard controls ---
143+
window.addEventListener("keydown", (e) => {
144+
switch (e.key.toLowerCase()) {
145+
case "arrowright": targetFrame = Math.min(frameCount, targetFrame + 1); break;
146+
case "arrowleft": targetFrame = Math.max(1, targetFrame - 1); break;
147+
case " ": isPlaying = !isPlaying; break;
148+
case "r": targetFrame = 1; break;
149+
case "l": targetFrame = frameCount; break;
150+
case "+": scale = Math.min(2, scale + 0.1); break;
151+
case "-": scale = Math.max(0.5, scale - 0.1); break;
152+
case "h":
153+
helpVisible = !helpVisible;
154+
helpOverlay.style.opacity = helpVisible ? 1 : 0;
155+
break;
156+
}
157+
});
158+
159+
// --- Help overlay auto-hide + toggle ---
160+
const helpOverlay = document.getElementById("help-overlay");
161+
let helpVisible = true;
162+
setTimeout(() => {
163+
helpOverlay.style.opacity = 0;
164+
helpVisible = false;
165+
}, 5000);
166+
167+
// --- Draggable help overlay (desktop only) ---
168+
let offsetX, offsetY, isDragging = false;
169+
helpOverlay.addEventListener("mousedown", (e) => {
170+
isDragging = true;
171+
offsetX = e.clientX - helpOverlay.getBoundingClientRect().left;
172+
offsetY = e.clientY - helpOverlay.getBoundingClientRect().top;
173+
helpOverlay.style.transition = "none";
174+
});
175+
window.addEventListener("mousemove", (e) => {
176+
if (isDragging) {
177+
helpOverlay.style.left = (e.clientX - offsetX) + "px";
178+
helpOverlay.style.top = (e.clientY - offsetY) + "px";
179+
helpOverlay.style.right = "auto";
180+
}
181+
});
182+
window.addEventListener("mouseup", () => {
183+
if (isDragging) {
184+
isDragging = false;
185+
helpOverlay.style.transition = "opacity 0.6s ease";
186+
}
187+
});
132188
</script>
133189
</body>
134190
</html>

0 commit comments

Comments
 (0)