Compare commits
3 Commits
e454a48532
...
9fc4eb09b7
| Author | SHA1 | Date | |
|---|---|---|---|
| 9fc4eb09b7 | |||
| fd5a0230f1 | |||
| d7bca21bd7 |
@@ -144,5 +144,14 @@ useKeyDown(({ key, repeated }) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const forceAnimateBLabel = () =>
|
||||||
|
animateLabelChange(
|
||||||
|
(v) => (bButtonOffsetY = v),
|
||||||
|
(l) => (displayedBLabel = l),
|
||||||
|
props.bLabel,
|
||||||
|
);
|
||||||
|
|
||||||
|
defineExpose({ forceAnimateBLabel });
|
||||||
|
|
||||||
defineOptions({ render: () => null });
|
defineOptions({ render: () => null });
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ const props = defineProps<{
|
|||||||
const confetti = useConfetti();
|
const confetti = useConfetti();
|
||||||
const { onRender } = useScreen();
|
const { onRender } = useScreen();
|
||||||
|
|
||||||
onRender((ctx) => {
|
onRender((ctx, deltaTime) => {
|
||||||
let offset: number;
|
let offset: number;
|
||||||
if (props.screen === "top") {
|
if (props.screen === "top") {
|
||||||
confetti.update();
|
confetti.update(deltaTime);
|
||||||
offset = 0;
|
offset = 0;
|
||||||
} else {
|
} else {
|
||||||
offset = LOGICAL_HEIGHT;
|
offset = LOGICAL_HEIGHT;
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ const BUTTONS = {
|
|||||||
git: {
|
git: {
|
||||||
position: [31, 32],
|
position: [31, 32],
|
||||||
action: "open",
|
action: "open",
|
||||||
url: "https://git.pihkaal.xyz",
|
url: "https://git.pihkaal.me",
|
||||||
text: "git.pihkaal.xyz",
|
text: "git.pihkaal.me",
|
||||||
},
|
},
|
||||||
email: {
|
email: {
|
||||||
position: [31, 64],
|
position: [31, 64],
|
||||||
|
|||||||
@@ -12,16 +12,17 @@ const { onRender, onClick } = useScreen();
|
|||||||
const BAR_HEIGHT = 24;
|
const BAR_HEIGHT = 24;
|
||||||
const MAX_RADIUS = 27;
|
const MAX_RADIUS = 27;
|
||||||
const MIN_RADIUS = 3;
|
const MIN_RADIUS = 3;
|
||||||
const BASE_SHRINK_SPEED = 0.09;
|
const BASE_SHRINK_SPEED = 0.18;
|
||||||
const MAX_SHRINK_SPEED = 0.14;
|
const MAX_SHRINK_SPEED = 0.28;
|
||||||
const BASE_SPAWN_INTERVAL = 90;
|
const BASE_SPAWN_INTERVAL = 45;
|
||||||
const MIN_SPAWN_INTERVAL = 45;
|
const MIN_SPAWN_INTERVAL = 23;
|
||||||
const DIFFICULTY_SCORE_CAP = 100;
|
const DIFFICULTY_SCORE_CAP = 100;
|
||||||
const RING_STROKE_WIDTH = 5;
|
const RING_STROKE_WIDTH = 5;
|
||||||
const RING_EXPAND_SPEED = 0.3;
|
const RING_EXPAND_SPEED = 0.6;
|
||||||
const RING_FADE_SPEED = 0.05;
|
const RING_FADE_SPEED = 0.1;
|
||||||
const MAX_LIVES = 3;
|
const MAX_LIVES = 3;
|
||||||
const CROSSHAIR_MOVE_SPEED = 5;
|
const CROSSHAIR_MOVE_SPEED = 10;
|
||||||
|
const FRAME_TIME = 1000 / 60;
|
||||||
|
|
||||||
const getDifficulty = () => {
|
const getDifficulty = () => {
|
||||||
const progress = Math.min(score / DIFFICULTY_SCORE_CAP, 1);
|
const progress = Math.min(score / DIFFICULTY_SCORE_CAP, 1);
|
||||||
@@ -120,7 +121,7 @@ const animateIntro = async () => {
|
|||||||
const animateOutro = async () => {
|
const animateOutro = async () => {
|
||||||
isAnimating.value = true;
|
isAnimating.value = true;
|
||||||
targetX = 0;
|
targetX = 0;
|
||||||
targetY = LOGICAL_HEIGHT * 2 - 20;
|
targetY = LOGICAL_HEIGHT;
|
||||||
|
|
||||||
await gsap
|
await gsap
|
||||||
.timeline({
|
.timeline({
|
||||||
@@ -200,12 +201,12 @@ const handleActivateA = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const moveTowards = (current: number, target: number) => {
|
const moveTowards = (current: number, target: number, dt: number) => {
|
||||||
if (current === target) return current;
|
if (current === target) return current;
|
||||||
const direction = Math.sign(target - current);
|
const direction = Math.sign(target - current);
|
||||||
return (
|
return (
|
||||||
current +
|
current +
|
||||||
direction * Math.min(CROSSHAIR_MOVE_SPEED, Math.abs(target - current))
|
direction * Math.min(CROSSHAIR_MOVE_SPEED * dt, Math.abs(target - current))
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -303,15 +304,17 @@ onClick((mx, my) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onRender((ctx) => {
|
onRender((ctx, deltaTime) => {
|
||||||
|
const dt = deltaTime / FRAME_TIME;
|
||||||
|
|
||||||
// update crosshair position in all modes except paused
|
// update crosshair position in all modes except paused
|
||||||
if (state.value !== "paused") {
|
if (state.value !== "paused") {
|
||||||
if (horizontalFirst) {
|
if (horizontalFirst) {
|
||||||
if (x !== targetX) x = moveTowards(x, targetX);
|
if (x !== targetX) x = moveTowards(x, targetX, dt);
|
||||||
else y = moveTowards(y, targetY);
|
else y = moveTowards(y, targetY, dt);
|
||||||
} else {
|
} else {
|
||||||
if (y !== targetY) y = moveTowards(y, targetY);
|
if (y !== targetY) y = moveTowards(y, targetY, dt);
|
||||||
else x = moveTowards(x, targetX);
|
else x = moveTowards(x, targetX, dt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,15 +323,15 @@ onRender((ctx) => {
|
|||||||
const { shrinkSpeed, spawnInterval } = getDifficulty();
|
const { shrinkSpeed, spawnInterval } = getDifficulty();
|
||||||
|
|
||||||
// spawn circles
|
// spawn circles
|
||||||
spawnTimer++;
|
spawnTimer += deltaTime;
|
||||||
if (spawnTimer >= spawnInterval) {
|
if (spawnTimer >= spawnInterval * FRAME_TIME) {
|
||||||
spawnCircle();
|
spawnCircle();
|
||||||
spawnTimer = 0;
|
spawnTimer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update circles and rings
|
// update circles and rings
|
||||||
circles = circles.filter((circle) => {
|
circles = circles.filter((circle) => {
|
||||||
circle.radius -= shrinkSpeed;
|
circle.radius -= shrinkSpeed * dt;
|
||||||
if (circle.radius < MIN_RADIUS) {
|
if (circle.radius < MIN_RADIUS) {
|
||||||
lives--;
|
lives--;
|
||||||
if (lives <= 0) {
|
if (lives <= 0) {
|
||||||
@@ -341,8 +344,8 @@ onRender((ctx) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
rings = rings.filter((ring) => {
|
rings = rings.filter((ring) => {
|
||||||
ring.radius += RING_EXPAND_SPEED;
|
ring.radius += RING_EXPAND_SPEED * dt;
|
||||||
ring.alpha -= RING_FADE_SPEED;
|
ring.alpha -= RING_FADE_SPEED * dt;
|
||||||
return ring.alpha > 0;
|
return ring.alpha > 0;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
const PARTICLE_COUNT = 400;
|
const PARTICLE_COUNT = 400;
|
||||||
const SPAWN_DURATION = 700;
|
const SPAWN_DURATION = 350;
|
||||||
const VX_RANGE = 0.5;
|
const VX_RANGE = 1.0;
|
||||||
const VY_MIN = 0.3;
|
const VY_MIN = 0.6;
|
||||||
const VY_RANGE = 0.2;
|
const VY_RANGE = 0.4;
|
||||||
const WIDTH_MIN = 3;
|
const WIDTH_MIN = 3;
|
||||||
const WIDTH_RANGE = 4;
|
const WIDTH_RANGE = 4;
|
||||||
const HEIGHT_MIN = 2;
|
const HEIGHT_MIN = 2;
|
||||||
const HEIGHT_RANGE = 3;
|
const HEIGHT_RANGE = 3;
|
||||||
const ROTATION_SPEED_RANGE = 0.15;
|
const ROTATION_SPEED_RANGE = 0.3;
|
||||||
const DRIFT_STRENGTH = 0.03;
|
const DRIFT_STRENGTH = 0.06;
|
||||||
const GRAVITY = 0.007;
|
const GRAVITY = 0.014;
|
||||||
const VX_DAMPING = 0.995;
|
const VX_DAMPING = 0.988;
|
||||||
const SWAY_AMPLITUDE = 0.3;
|
const SWAY_AMPLITUDE = 0.6;
|
||||||
const SWAY_SPEED_MIN = 0.02;
|
const SWAY_SPEED_MIN = 0.04;
|
||||||
const SWAY_SPEED_RANGE = 0.03;
|
const SWAY_SPEED_RANGE = 0.06;
|
||||||
const OFFSCREEN_MARGIN = 10;
|
const OFFSCREEN_MARGIN = 10;
|
||||||
const TOTAL_HEIGHT = 192 * 2;
|
const TOTAL_HEIGHT = 192 * 2;
|
||||||
|
const FRAME_TIME = 1000 / 60;
|
||||||
|
|
||||||
const COLORS = [
|
const COLORS = [
|
||||||
"#fb0018",
|
"#fb0018",
|
||||||
@@ -41,7 +42,7 @@ export type ConfettiParticle = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type Spawner = {
|
type Spawner = {
|
||||||
frame: number;
|
elapsed: number;
|
||||||
accumulator: number;
|
accumulator: number;
|
||||||
particleCount: number;
|
particleCount: number;
|
||||||
duration: number;
|
duration: number;
|
||||||
@@ -67,18 +68,25 @@ const spawnParticle = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const spawn = (particleCount = PARTICLE_COUNT, duration = SPAWN_DURATION) => {
|
const spawn = (particleCount = PARTICLE_COUNT, duration = SPAWN_DURATION) => {
|
||||||
spawners.push({ frame: 0, accumulator: 0, particleCount, duration });
|
spawners.push({
|
||||||
|
elapsed: 0,
|
||||||
|
accumulator: 0,
|
||||||
|
particleCount,
|
||||||
|
duration: duration * FRAME_TIME,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const update = () => {
|
const update = (deltaTime: number) => {
|
||||||
|
const dt = deltaTime / FRAME_TIME;
|
||||||
|
|
||||||
for (let s = spawners.length - 1; s >= 0; s -= 1) {
|
for (let s = spawners.length - 1; s >= 0; s -= 1) {
|
||||||
const spawner = spawners[s]!;
|
const spawner = spawners[s]!;
|
||||||
if (spawner.frame < spawner.duration) {
|
if (spawner.elapsed < spawner.duration) {
|
||||||
const progress = spawner.frame / spawner.duration;
|
const progress = spawner.elapsed / spawner.duration;
|
||||||
const inv = 1 - progress;
|
const inv = 1 - progress;
|
||||||
const rate = inv * inv;
|
const rate = inv * inv;
|
||||||
spawner.accumulator +=
|
spawner.accumulator +=
|
||||||
rate * (spawner.particleCount / spawner.duration) * 3;
|
rate * (spawner.particleCount / spawner.duration) * 3 * deltaTime;
|
||||||
|
|
||||||
const count = Math.floor(spawner.accumulator);
|
const count = Math.floor(spawner.accumulator);
|
||||||
spawner.accumulator -= count;
|
spawner.accumulator -= count;
|
||||||
@@ -87,7 +95,7 @@ const update = () => {
|
|||||||
spawnParticle();
|
spawnParticle();
|
||||||
}
|
}
|
||||||
|
|
||||||
spawner.frame += 1;
|
spawner.elapsed += deltaTime;
|
||||||
} else {
|
} else {
|
||||||
spawners.splice(s, 1);
|
spawners.splice(s, 1);
|
||||||
}
|
}
|
||||||
@@ -95,13 +103,13 @@ const update = () => {
|
|||||||
|
|
||||||
for (let i = particles.length - 1; i >= 0; i -= 1) {
|
for (let i = particles.length - 1; i >= 0; i -= 1) {
|
||||||
const p = particles[i]!;
|
const p = particles[i]!;
|
||||||
p.vy += GRAVITY;
|
p.vy += GRAVITY * dt;
|
||||||
p.vx += (Math.random() - 0.5) * DRIFT_STRENGTH;
|
p.vx += (Math.random() - 0.5) * DRIFT_STRENGTH * dt;
|
||||||
p.vx *= VX_DAMPING;
|
p.vx *= Math.pow(VX_DAMPING, dt);
|
||||||
p.swayPhase += p.swaySpeed;
|
p.swayPhase += p.swaySpeed * dt;
|
||||||
p.x += p.vx + Math.sin(p.swayPhase) * SWAY_AMPLITUDE;
|
p.x += (p.vx + Math.sin(p.swayPhase) * SWAY_AMPLITUDE) * dt;
|
||||||
p.y += p.vy;
|
p.y += p.vy * dt;
|
||||||
p.rotation += p.rotationSpeed;
|
p.rotation += p.rotationSpeed * dt;
|
||||||
|
|
||||||
if (p.y > TOTAL_HEIGHT + OFFSCREEN_MARGIN) {
|
if (p.y > TOTAL_HEIGHT + OFFSCREEN_MARGIN) {
|
||||||
particles.splice(i, 1);
|
particles.splice(i, 1);
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export const useAchievementsStore = defineStore("achievements", () => {
|
|||||||
if (storage.value.unlocked.length === ACHIEVEMENTS.length) {
|
if (storage.value.unlocked.length === ACHIEVEMENTS.length) {
|
||||||
confetti.spawn();
|
confetti.spawn();
|
||||||
} else {
|
} else {
|
||||||
confetti.spawn(50, 350);
|
confetti.spawn(50, 175);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
order: 50
|
order: 50
|
||||||
scope: hobby
|
scope: hobby
|
||||||
title: LBF Bot
|
title: LBF Bot
|
||||||
link: https://git.pihkaal.xyz/lbf-bot
|
link: https://git.pihkaal.me/lbf-bot
|
||||||
|
|
||||||
description: For a gaming group
|
description: For a gaming group
|
||||||
summary: Custom Discord bot
|
summary: Custom Discord bot
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
order: 60
|
order: 60
|
||||||
scope: hobby
|
scope: hobby
|
||||||
title: Raylib Spdrns
|
title: Raylib Spdrns
|
||||||
link: https://git.pihkaal.xyz/raylib-speedruns
|
link: https://git.pihkaal.me/raylib-speedruns
|
||||||
|
|
||||||
description: Awesome video game library
|
description: Awesome video game library
|
||||||
summary: Raylib Speedruns
|
summary: Raylib Speedruns
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
order: 20
|
order: 20
|
||||||
scope: hobby
|
scope: hobby
|
||||||
title: tlock
|
title: tlock
|
||||||
link: https://git.pihkaal.xyz/tlock
|
link: https://git.pihkaal.me/tlock
|
||||||
|
|
||||||
description: For Hyprland ricing
|
description: For Hyprland ricing
|
||||||
summary: Terminal based clock
|
summary: Terminal based clock
|
||||||
|
|||||||
@@ -161,7 +161,7 @@
|
|||||||
"actions": {
|
"actions": {
|
||||||
"open": "Open",
|
"open": "Open",
|
||||||
"copy": "Copy",
|
"copy": "Copy",
|
||||||
"git": "Github profile",
|
"git": "Git page",
|
||||||
"email": "Email",
|
"email": "Email",
|
||||||
"linkedin": "LinkedIn link",
|
"linkedin": "LinkedIn link",
|
||||||
"cv": "CV"
|
"cv": "CV"
|
||||||
|
|||||||
Reference in New Issue
Block a user