diff --git a/public/images/coralz_0.png b/public/images/coralz_0.png new file mode 100644 index 0000000..d9b729f Binary files /dev/null and b/public/images/coralz_0.png differ diff --git a/public/images/coralz_1.png b/public/images/coralz_1.png new file mode 100644 index 0000000..d4a8f7d Binary files /dev/null and b/public/images/coralz_1.png differ diff --git a/public/sound/poke.wav b/public/sound/poke.wav new file mode 100644 index 0000000..790c901 Binary files /dev/null and b/public/sound/poke.wav differ diff --git a/public/sound/squeak.wav b/public/sound/squeak.wav new file mode 100644 index 0000000..7d118c6 Binary files /dev/null and b/public/sound/squeak.wav differ diff --git a/src/app/globals.css b/src/app/globals.css index 12f9857..de2db22 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -7,6 +7,17 @@ --primary: #F48120; } +@keyframes click-bounce { + 0%, 100% { + transform: scale(1, 1); + /* animation-timing-function: linear(0.2, 0.8, 1); */ + } + 30% { + transform: scale(1.18, 0.9); + /* animation-timing-function: cubic-bezier(0.8, 0, 1, 1); */ + } +} + @keyframes silly-bounce { 0%, 100% { transform: translate(0px, 0px) scale(0.9, 1.1); diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx index e1473c6..fef25ba 100644 --- a/src/app/not-found.tsx +++ b/src/app/not-found.tsx @@ -1,4 +1,6 @@ +import WobblingImage from "@/components/wobbling-image"; import type { Metadata } from "next"; +import Link from "@/components/link"; export const metadata: Metadata = { title: "Wep wep", @@ -8,12 +10,19 @@ export default function NotFound() { return (
-
-

404

-
-
- Oh you lost, you know there's nothing here... -
+ + + Source
); diff --git a/src/app/page.tsx b/src/app/page.tsx index 51651af..d648a39 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -3,9 +3,8 @@ import { NolaGlitchClientOnly } from "@/components/nola-glitch"; import { Sosmed } from "@/components/sosmed"; import HomeText from "@/components/home-text.mdx" -import Link from "next/link"; +import Link from "@/components/link"; import { FakeWindow, HomeWindows } from "@/components/windows"; -import Taskbar from "@/components/taskbar"; import { WindowManagerProvider } from "@/hooks/window-manager"; export default function Home() { @@ -28,12 +27,12 @@ export default function Home() {
-

⚡ Powered with Cloudflare ☁️

+

⚡ Powered with Cloudflare ☁️

diff --git a/src/components/link.tsx b/src/components/link.tsx new file mode 100644 index 0000000..00134f5 --- /dev/null +++ b/src/components/link.tsx @@ -0,0 +1,14 @@ +import clsx from "clsx"; +import NextLink from "next/link" + +function Link({ className, ...props }: React.ComponentProps) { + return ( + + ) +} + + +export default Link; \ No newline at end of file diff --git a/src/components/page-template.tsx b/src/components/page-template.tsx index 9a6febf..488234f 100644 --- a/src/components/page-template.tsx +++ b/src/components/page-template.tsx @@ -15,7 +15,7 @@ export const SimpleArticle = ({ Back -
+
{children}
diff --git a/src/components/texts/privacy.mdx b/src/components/texts/privacy.mdx index 2cba190..d8839b9 100644 --- a/src/components/texts/privacy.mdx +++ b/src/components/texts/privacy.mdx @@ -1,5 +1,5 @@ # Privacy Policy -This website ("nonszy.space") fully respects the privacy of its visitors. This document explains how we handle visitor information. The short answer is: **we do not collect, track, or store your personal information**. +This website ("nonszy.space") fully respects the privacy of its visitors. This page explains how we handle visitor information. The short answer is: **we do not collect, track, or store your personal information**. However, future feature additions will update the privacy policy. \ No newline at end of file diff --git a/src/components/wobbling-image.tsx b/src/components/wobbling-image.tsx new file mode 100644 index 0000000..169eda1 --- /dev/null +++ b/src/components/wobbling-image.tsx @@ -0,0 +1,132 @@ +'use client' + +import clsx from "clsx"; +import Image from "next/image"; +import { useCallback, useEffect, useRef, useState } from "react" + +interface WobblingImageInterface { + img1: string + img2?: string +} + +function WobblingImage ({ + img1, img2 +}: WobblingImageInterface) { + const size = 400; + const [isAnimating, setIsAnimating] = useState(false); + + const audioPath = "/sound/poke.wav"; + const audioContextRef = useRef(null); + const [audioBuffer, setAudioBuffer] = useState(null); + const [audioLoaded, setAudioLoaded] = useState(false); + + const [dummyAudio, setDummyAudio] = useState(null); + + useEffect(() => { + if (typeof Audio !== undefined) setDummyAudio(new Audio(audioPath)) + return () => { + if (dummyAudio) dummyAudio.pause(); + } + }, []) + + const initializeAudioContext = useCallback((): AudioContext => { + if (!audioContextRef.current) { + audioContextRef.current = new (window.AudioContext || (window as any).webkitAudioContext)(); + } + return audioContextRef.current; + }, []); + + const loadAudio = useCallback(async (url: string): Promise => { + const response = await fetch(url); + const arrayBuffer = await response.arrayBuffer(); + const context = initializeAudioContext(); + return await context.decodeAudioData(arrayBuffer); + }, [initializeAudioContext]); + + const initializeAudio = useCallback(async (): Promise => { + if (audioBuffer) return; + + setAudioLoaded(false); + try { + const buffer = await loadAudio(audioPath); + setAudioBuffer(buffer); + } catch (error) { + console.error('Failed to load audio:', error); + } + finally { + setAudioLoaded(true); + } + }, [audioBuffer, loadAudio]); + + const playRandomPitch = useCallback(async (): Promise => { + await initializeAudio(); + + if (!audioBuffer || !audioContextRef.current) return; + + const context = audioContextRef.current; + const changeToLowPitch = Math.floor(Math.random() * 10); + const randomPitch = Math.random() * 0.2 + (changeToLowPitch == 1 ? 0.25 : 0.85); + + const source = context.createBufferSource(); + source.buffer = audioBuffer; + source.playbackRate.value = randomPitch; + source.connect(context.destination); + source.start(0); + + source.onended = () => { + source.disconnect(); + }; + }, [audioBuffer, initializeAudio]); + + + function handleClick() { + setIsAnimating(false); + requestAnimationFrame(() => setIsAnimating(true)); + playRandomPitch(); + if (dummyAudio && !audioLoaded) { + dummyAudio.currentTime = 0; + dummyAudio.play(); + } + } + + function handleAnimationEnd() { + setIsAnimating(false); + } + + return ( +
+
{ if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); handleClick(); } }} + onMouseDown={(e) => e.preventDefault()} + onPointerDown={(e) => e.preventDefault()} + > + clip1 + clip2 +
+
+ ) +} + +export default WobblingImage; \ No newline at end of file diff --git a/tailwind.config.ts b/tailwind.config.ts index 7fce617..4f7a79f 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -24,6 +24,7 @@ const config: Config = { }, animation: { "silly-bouncing": 'silly-bounce 0.8s infinite', + "click-bouncing": 'click-bounce 200ms', 'window-popup': 'window-popup 1s', 'window-popdown': 'window-popdown 1s' },