From 878216e4a44fab542d0be40dfb419dd6bcb40c95 Mon Sep 17 00:00:00 2001 From: kim dohun Date: Wed, 13 Aug 2025 22:12:30 +0900 Subject: [PATCH 1/2] feat: add mobile touch support for Hyperspeed component --- .../Backgrounds/Hyperspeed/Hyperspeed.jsx | 23 ++++++++++++ .../Backgrounds/Hyperspeed/Hyperspeed.jsx | 23 ++++++++++++ .../Backgrounds/Hyperspeed/Hyperspeed.tsx | 27 +++++++++++++- .../Backgrounds/Hyperspeed/Hyperspeed.tsx | 37 +++++++++++++++++-- 4 files changed, 104 insertions(+), 6 deletions(-) diff --git a/src/content/Backgrounds/Hyperspeed/Hyperspeed.jsx b/src/content/Backgrounds/Hyperspeed/Hyperspeed.jsx index 7377c54d..da35fec6 100644 --- a/src/content/Backgrounds/Hyperspeed/Hyperspeed.jsx +++ b/src/content/Backgrounds/Hyperspeed/Hyperspeed.jsx @@ -413,6 +413,9 @@ const Hyperspeed = ({ effectOptions = { this.setSize = this.setSize.bind(this); this.onMouseDown = this.onMouseDown.bind(this); this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); window.addEventListener("resize", this.onWindowResize.bind(this)); } @@ -500,6 +503,10 @@ const Hyperspeed = ({ effectOptions = { this.container.addEventListener("mousedown", this.onMouseDown); this.container.addEventListener("mouseup", this.onMouseUp); this.container.addEventListener("mouseout", this.onMouseUp); + + this.container.addEventListener("touchstart", this.onTouchStart, { passive: true }); + this.container.addEventListener("touchend", this.onTouchEnd, { passive: true }); + this.container.addEventListener("touchcancel", this.onTouchEnd, { passive: true }); this.tick(); } @@ -516,6 +523,18 @@ const Hyperspeed = ({ effectOptions = { this.speedUpTarget = 0; } + onTouchStart(ev) { + if (this.options.onSpeedUp) this.options.onSpeedUp(ev); + this.fovTarget = this.options.fovSpeedUp; + this.speedUpTarget = this.options.speedUp; + } + + onTouchEnd(ev) { + if (this.options.onSlowDown) this.options.onSlowDown(ev); + this.fovTarget = this.options.fov; + this.speedUpTarget = 0; + } + update(delta) { let lerpPercentage = Math.exp(-(-60 * Math.log2(1 - 0.1)) * delta); this.speedUp += lerp( @@ -584,6 +603,10 @@ const Hyperspeed = ({ effectOptions = { this.container.removeEventListener("mousedown", this.onMouseDown); this.container.removeEventListener("mouseup", this.onMouseUp); this.container.removeEventListener("mouseout", this.onMouseUp); + + this.container.removeEventListener("touchstart", this.onTouchStart); + this.container.removeEventListener("touchend", this.onTouchEnd); + this.container.removeEventListener("touchcancel", this.onTouchEnd); } } diff --git a/src/tailwind/Backgrounds/Hyperspeed/Hyperspeed.jsx b/src/tailwind/Backgrounds/Hyperspeed/Hyperspeed.jsx index 5e32d7dc..3a90acd2 100644 --- a/src/tailwind/Backgrounds/Hyperspeed/Hyperspeed.jsx +++ b/src/tailwind/Backgrounds/Hyperspeed/Hyperspeed.jsx @@ -412,6 +412,9 @@ const Hyperspeed = ({ effectOptions = { this.setSize = this.setSize.bind(this); this.onMouseDown = this.onMouseDown.bind(this); this.onMouseUp = this.onMouseUp.bind(this); + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); window.addEventListener("resize", this.onWindowResize.bind(this)); } @@ -500,6 +503,10 @@ const Hyperspeed = ({ effectOptions = { this.container.addEventListener("mouseup", this.onMouseUp); this.container.addEventListener("mouseout", this.onMouseUp); + this.container.addEventListener("touchstart", this.onTouchStart, { passive: true }); + this.container.addEventListener("touchend", this.onTouchEnd, { passive: true }); + this.container.addEventListener("touchcancel", this.onTouchEnd, { passive: true }); + this.tick(); } @@ -514,6 +521,18 @@ const Hyperspeed = ({ effectOptions = { this.fovTarget = this.options.fov; this.speedUpTarget = 0; } + + onTouchStart(ev) { + if (this.options.onSpeedUp) this.options.onSpeedUp(ev); + this.fovTarget = this.options.fovSpeedUp; + this.speedUpTarget = this.options.speedUp; + } + + onTouchEnd(ev) { + if (this.options.onSlowDown) this.options.onSlowDown(ev); + this.fovTarget = this.options.fov; + this.speedUpTarget = 0; + } update(delta) { let lerpPercentage = Math.exp(-(-60 * Math.log2(1 - 0.1)) * delta); @@ -582,6 +601,10 @@ const Hyperspeed = ({ effectOptions = { this.container.removeEventListener("mousedown", this.onMouseDown); this.container.removeEventListener("mouseup", this.onMouseUp); this.container.removeEventListener("mouseout", this.onMouseUp); + + this.container.removeEventListener("touchstart", this.onTouchStart); + this.container.removeEventListener("touchend", this.onTouchEnd); + this.container.removeEventListener("touchcancel", this.onTouchEnd); } } diff --git a/src/ts-default/Backgrounds/Hyperspeed/Hyperspeed.tsx b/src/ts-default/Backgrounds/Hyperspeed/Hyperspeed.tsx index e3b406a0..04009baf 100644 --- a/src/ts-default/Backgrounds/Hyperspeed/Hyperspeed.tsx +++ b/src/ts-default/Backgrounds/Hyperspeed/Hyperspeed.tsx @@ -33,8 +33,8 @@ interface Colors { } interface HyperspeedOptions { - onSpeedUp?: (ev: MouseEvent) => void; - onSlowDown?: (ev: MouseEvent) => void; + onSpeedUp?: (ev: MouseEvent | TouchEvent) => void; + onSlowDown?: (ev: MouseEvent | TouchEvent) => void; distortion?: string | Distortion; length: number; roadWidth: number; @@ -1074,6 +1074,9 @@ class App { this.onMouseDown = this.onMouseDown.bind(this); this.onMouseUp = this.onMouseUp.bind(this); + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + window.addEventListener("resize", this.onWindowResize.bind(this)); } @@ -1162,6 +1165,10 @@ class App { this.container.addEventListener("mousedown", this.onMouseDown); this.container.addEventListener("mouseup", this.onMouseUp); this.container.addEventListener("mouseout", this.onMouseUp); + + this.container.addEventListener("touchstart", this.onTouchStart, { passive: true }); + this.container.addEventListener("touchend", this.onTouchEnd, { passive: true }); + this.container.addEventListener("touchcancel", this.onTouchEnd, { passive: true }); this.tick(); } @@ -1177,6 +1184,18 @@ class App { this.fovTarget = this.options.fov; this.speedUpTarget = 0; } + + onTouchStart(ev: TouchEvent) { + if (this.options.onSpeedUp) this.options.onSpeedUp(ev); + this.fovTarget = this.options.fovSpeedUp; + this.speedUpTarget = this.options.speedUp; + } + + onTouchEnd(ev: TouchEvent) { + if (this.options.onSlowDown) this.options.onSlowDown(ev); + this.fovTarget = this.options.fov; + this.speedUpTarget = 0; + } update(delta: number) { const lerpPercentage = Math.exp(-(-60 * Math.log2(1 - 0.1)) * delta); @@ -1243,6 +1262,10 @@ class App { this.container.removeEventListener("mousedown", this.onMouseDown); this.container.removeEventListener("mouseup", this.onMouseUp); this.container.removeEventListener("mouseout", this.onMouseUp); + + this.container.removeEventListener("touchstart", this.onTouchStart); + this.container.removeEventListener("touchend", this.onTouchEnd); + this.container.removeEventListener("touchcancel", this.onTouchEnd); } } diff --git a/src/ts-tailwind/Backgrounds/Hyperspeed/Hyperspeed.tsx b/src/ts-tailwind/Backgrounds/Hyperspeed/Hyperspeed.tsx index f5e351df..eed121b3 100644 --- a/src/ts-tailwind/Backgrounds/Hyperspeed/Hyperspeed.tsx +++ b/src/ts-tailwind/Backgrounds/Hyperspeed/Hyperspeed.tsx @@ -31,8 +31,8 @@ interface Colors { } interface HyperspeedOptions { - onSpeedUp?: (ev: MouseEvent) => void; - onSlowDown?: (ev: MouseEvent) => void; + onSpeedUp?: (ev: MouseEvent | TouchEvent) => void; + onSlowDown?: (ev: MouseEvent | TouchEvent) => void; distortion?: string | Distortion; length: number; roadWidth: number; @@ -1075,7 +1075,10 @@ class App { this.setSize = this.setSize.bind(this); this.onMouseDown = this.onMouseDown.bind(this); this.onMouseUp = this.onMouseUp.bind(this); - + + this.onTouchStart = this.onTouchStart.bind(this); + this.onTouchEnd = this.onTouchEnd.bind(this); + window.addEventListener("resize", this.onWindowResize.bind(this)); } @@ -1165,6 +1168,16 @@ class App { this.container.addEventListener("mouseup", this.onMouseUp); this.container.addEventListener("mouseout", this.onMouseUp); + this.container.addEventListener("touchstart", this.onTouchStart, { + passive: true, + }); + this.container.addEventListener("touchend", this.onTouchEnd, { + passive: true, + }); + this.container.addEventListener("touchcancel", this.onTouchEnd, { + passive: true, + }); + this.tick(); } @@ -1180,6 +1193,18 @@ class App { this.speedUpTarget = 0; } + onTouchStart(ev: TouchEvent) { + if (this.options.onSpeedUp) this.options.onSpeedUp(ev); + this.fovTarget = this.options.fovSpeedUp; + this.speedUpTarget = this.options.speedUp; + } + + onTouchEnd(ev: TouchEvent) { + if (this.options.onSlowDown) this.options.onSlowDown(ev); + this.fovTarget = this.options.fov; + this.speedUpTarget = 0; + } + update(delta: number) { const lerpPercentage = Math.exp(-(-60 * Math.log2(1 - 0.1)) * delta); this.speedUp += lerp( @@ -1239,12 +1264,16 @@ class App { if (this.scene) { this.scene.clear(); } - + window.removeEventListener("resize", this.onWindowResize.bind(this)); if (this.container) { this.container.removeEventListener("mousedown", this.onMouseDown); this.container.removeEventListener("mouseup", this.onMouseUp); this.container.removeEventListener("mouseout", this.onMouseUp); + + this.container.removeEventListener("touchstart", this.onTouchStart); + this.container.removeEventListener("touchend", this.onTouchEnd); + this.container.removeEventListener("touchcancel", this.onTouchEnd); } } From 09e5229cb4a44c30a68b58c4906120e45507f03a Mon Sep 17 00:00:00 2001 From: kim dohun Date: Wed, 13 Aug 2025 23:23:53 +0900 Subject: [PATCH 2/2] fix: disable context menu and text selection for better touch UX --- src/content/Backgrounds/Hyperspeed/Hyperspeed.jsx | 8 ++++++++ src/tailwind/Backgrounds/Hyperspeed/Hyperspeed.jsx | 7 +++++++ src/ts-default/Backgrounds/Hyperspeed/Hyperspeed.tsx | 7 +++++++ src/ts-tailwind/Backgrounds/Hyperspeed/Hyperspeed.tsx | 7 +++++++ 4 files changed, 29 insertions(+) diff --git a/src/content/Backgrounds/Hyperspeed/Hyperspeed.jsx b/src/content/Backgrounds/Hyperspeed/Hyperspeed.jsx index da35fec6..34ae53c4 100644 --- a/src/content/Backgrounds/Hyperspeed/Hyperspeed.jsx +++ b/src/content/Backgrounds/Hyperspeed/Hyperspeed.jsx @@ -416,6 +416,7 @@ const Hyperspeed = ({ effectOptions = { this.onTouchStart = this.onTouchStart.bind(this); this.onTouchEnd = this.onTouchEnd.bind(this); + this.onContextMenu = this.onContextMenu.bind(this); window.addEventListener("resize", this.onWindowResize.bind(this)); } @@ -507,6 +508,8 @@ const Hyperspeed = ({ effectOptions = { this.container.addEventListener("touchstart", this.onTouchStart, { passive: true }); this.container.addEventListener("touchend", this.onTouchEnd, { passive: true }); this.container.addEventListener("touchcancel", this.onTouchEnd, { passive: true }); + + this.container.addEventListener("contextmenu", this.onContextMenu); this.tick(); } @@ -535,6 +538,10 @@ const Hyperspeed = ({ effectOptions = { this.speedUpTarget = 0; } + onContextMenu(ev) { + ev.preventDefault(); + } + update(delta) { let lerpPercentage = Math.exp(-(-60 * Math.log2(1 - 0.1)) * delta); this.speedUp += lerp( @@ -607,6 +614,7 @@ const Hyperspeed = ({ effectOptions = { this.container.removeEventListener("touchstart", this.onTouchStart); this.container.removeEventListener("touchend", this.onTouchEnd); this.container.removeEventListener("touchcancel", this.onTouchEnd); + this.container.removeEventListener("contextmenu", this.onContextMenu); } } diff --git a/src/tailwind/Backgrounds/Hyperspeed/Hyperspeed.jsx b/src/tailwind/Backgrounds/Hyperspeed/Hyperspeed.jsx index 3a90acd2..202c50a7 100644 --- a/src/tailwind/Backgrounds/Hyperspeed/Hyperspeed.jsx +++ b/src/tailwind/Backgrounds/Hyperspeed/Hyperspeed.jsx @@ -415,6 +415,7 @@ const Hyperspeed = ({ effectOptions = { this.onTouchStart = this.onTouchStart.bind(this); this.onTouchEnd = this.onTouchEnd.bind(this); + this.onContextMenu = this.onContextMenu.bind(this); window.addEventListener("resize", this.onWindowResize.bind(this)); } @@ -506,6 +507,7 @@ const Hyperspeed = ({ effectOptions = { this.container.addEventListener("touchstart", this.onTouchStart, { passive: true }); this.container.addEventListener("touchend", this.onTouchEnd, { passive: true }); this.container.addEventListener("touchcancel", this.onTouchEnd, { passive: true }); + this.container.addEventListener("contextmenu", this.onContextMenu); this.tick(); } @@ -534,6 +536,10 @@ const Hyperspeed = ({ effectOptions = { this.speedUpTarget = 0; } + onContextMenu(ev) { + ev.preventDefault(); + } + update(delta) { let lerpPercentage = Math.exp(-(-60 * Math.log2(1 - 0.1)) * delta); this.speedUp += lerp( @@ -605,6 +611,7 @@ const Hyperspeed = ({ effectOptions = { this.container.removeEventListener("touchstart", this.onTouchStart); this.container.removeEventListener("touchend", this.onTouchEnd); this.container.removeEventListener("touchcancel", this.onTouchEnd); + this.container.removeEventListener("contextmenu", this.onContextMenu); } } diff --git a/src/ts-default/Backgrounds/Hyperspeed/Hyperspeed.tsx b/src/ts-default/Backgrounds/Hyperspeed/Hyperspeed.tsx index 04009baf..2e5d5d2c 100644 --- a/src/ts-default/Backgrounds/Hyperspeed/Hyperspeed.tsx +++ b/src/ts-default/Backgrounds/Hyperspeed/Hyperspeed.tsx @@ -1076,6 +1076,7 @@ class App { this.onTouchStart = this.onTouchStart.bind(this); this.onTouchEnd = this.onTouchEnd.bind(this); + this.onContextMenu = this.onContextMenu.bind(this); window.addEventListener("resize", this.onWindowResize.bind(this)); } @@ -1169,6 +1170,7 @@ class App { this.container.addEventListener("touchstart", this.onTouchStart, { passive: true }); this.container.addEventListener("touchend", this.onTouchEnd, { passive: true }); this.container.addEventListener("touchcancel", this.onTouchEnd, { passive: true }); + this.container.addEventListener("contextmenu", this.onContextMenu); this.tick(); } @@ -1197,6 +1199,10 @@ class App { this.speedUpTarget = 0; } + onContextMenu(ev: MouseEvent) { + ev.preventDefault(); + } + update(delta: number) { const lerpPercentage = Math.exp(-(-60 * Math.log2(1 - 0.1)) * delta); this.speedUp += lerp( @@ -1266,6 +1272,7 @@ class App { this.container.removeEventListener("touchstart", this.onTouchStart); this.container.removeEventListener("touchend", this.onTouchEnd); this.container.removeEventListener("touchcancel", this.onTouchEnd); + this.container.removeEventListener("contextmenu", this.onContextMenu); } } diff --git a/src/ts-tailwind/Backgrounds/Hyperspeed/Hyperspeed.tsx b/src/ts-tailwind/Backgrounds/Hyperspeed/Hyperspeed.tsx index eed121b3..d9a292c8 100644 --- a/src/ts-tailwind/Backgrounds/Hyperspeed/Hyperspeed.tsx +++ b/src/ts-tailwind/Backgrounds/Hyperspeed/Hyperspeed.tsx @@ -1078,6 +1078,7 @@ class App { this.onTouchStart = this.onTouchStart.bind(this); this.onTouchEnd = this.onTouchEnd.bind(this); + this.onContextMenu = this.onContextMenu.bind(this); window.addEventListener("resize", this.onWindowResize.bind(this)); } @@ -1177,6 +1178,7 @@ class App { this.container.addEventListener("touchcancel", this.onTouchEnd, { passive: true, }); + this.container.addEventListener("contextmenu", this.onContextMenu); this.tick(); } @@ -1205,6 +1207,10 @@ class App { this.speedUpTarget = 0; } + onContextMenu(ev: MouseEvent) { + ev.preventDefault(); + } + update(delta: number) { const lerpPercentage = Math.exp(-(-60 * Math.log2(1 - 0.1)) * delta); this.speedUp += lerp( @@ -1274,6 +1280,7 @@ class App { this.container.removeEventListener("touchstart", this.onTouchStart); this.container.removeEventListener("touchend", this.onTouchEnd); this.container.removeEventListener("touchcancel", this.onTouchEnd); + this.container.removeEventListener("contextmenu", this.onContextMenu); } }