| |
| |
| |
| |
| import { useEffect } from "react"; |
| import GameCanvas from "./scene/GameCanvas.jsx"; |
| import { Halftone, CrtOverlay } from "./ui/Overlays.jsx"; |
| import Hud from "./ui/Hud.jsx"; |
| import TouchOverlay from "./ui/TouchOverlay.jsx"; |
| import BiosOverlay from "./ui/BiosOverlay.jsx"; |
| import TitleMenu from "./ui/TitleMenu.jsx"; |
| import Preboot from "./ui/Preboot.jsx"; |
| import { useGame } from "./store.js"; |
| import { signed } from "./game/signed.js"; |
|
|
| export default function App() { |
| useEffect(() => { |
| const params = new URLSearchParams(location.search); |
|
|
| |
| |
| const pollPad = () => { |
| const gp = [...(navigator.getGamepads?.() ?? [])].find((p) => p && p.connected); |
| useGame.setState({ padConnected: !!gp }); |
| }; |
| window.addEventListener("gamepadconnected", pollPad); |
| window.addEventListener("gamepaddisconnected", pollPad); |
| pollPad(); |
|
|
| |
| |
| |
| |
| const coarse = matchMedia("(pointer: coarse)"); |
| const armTouch = () => { |
| window.__microduckTouched = true; |
| useGame.setState({ touchMode: true }); |
| }; |
| const onCoarse = () => coarse.matches && armTouch(); |
| if (coarse.matches) armTouch(); |
| else coarse.addEventListener("change", onCoarse); |
| window.addEventListener("touchstart", armTouch, { once: true, passive: true }); |
| if (params.get("touch") === "1") armTouch(); |
|
|
| |
| |
| |
| if (params.get("boot") === "1") { |
| useGame.setState({ prebootDone: true, entered: true, menuOpen: false }); |
| } else { |
| const img = new Image(); |
| img.src = signed("./assets/duck-head-mark.webp"); |
| const imgReady = new Promise((res) => { |
| if (img.complete && img.naturalWidth) res(); |
| else { |
| img.addEventListener("load", res, { once: true }); |
| img.addEventListener("error", res, { once: true }); |
| } |
| }); |
| const fontsReady = document.fonts?.ready ?? Promise.resolve(); |
| const cap = new Promise((res) => setTimeout(res, 2500)); |
| Promise.race([Promise.all([imgReady, fontsReady]), cap]).then(() => { |
| useGame.setState({ prebootDone: true, menuOpen: true }); |
| }); |
| } |
|
|
| return () => { |
| window.removeEventListener("gamepadconnected", pollPad); |
| window.removeEventListener("gamepaddisconnected", pollPad); |
| coarse.removeEventListener("change", onCoarse); |
| window.removeEventListener("touchstart", armTouch); |
| }; |
| }, []); |
|
|
| return ( |
| <> |
| <GameCanvas /> |
| <Halftone /> |
| <CrtOverlay /> |
| <Hud /> |
| <TouchOverlay /> |
| <BiosOverlay /> |
| <TitleMenu /> |
| <Preboot /> |
| </> |
| ); |
| } |
|
|