diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 26efc46..1353638 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,6 +8,7 @@ "name": "kira", "version": "0.1.0", "dependencies": { + "howler": "^2.2.4", "pixi-live2d-display": "^0.4.0", "pixi.js": "^7.4.3", "react": "^19.2.6", @@ -15,13 +16,14 @@ }, "devDependencies": { "@tailwindcss/vite": "^4.1.6", + "@types/howler": "^2.2.13", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", "autoprefixer": "^10.4.20", "postcss": "^8.5.3", "tailwindcss": "^4.1.6", - "typescript": "~6.0.2", + "typescript": "^6.0.3", "vite": "^8.0.12" } }, @@ -871,6 +873,13 @@ "integrity": "sha512-qp3m9PPz4gULB9MhjGID7wpo3gJ4bTGXm7ltNDsmOvsPduTeHp8wSW9YckBj3mljeOh4F0m2z/0JKAALRKbmLQ==", "license": "MIT" }, + "node_modules/@types/howler": { + "version": "2.2.13", + "resolved": "https://registry.npmjs.org/@types/howler/-/howler-2.2.13.tgz", + "integrity": "sha512-40+EBjqIHHrC4VShlz/7i0lBUsE3QkgzZinQQji74Hd8sBkJZUBaT7LWFLK6rcabsDOOQpoMbEJvtaFQwxOu/g==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/offscreencanvas": { "version": "2019.7.3", "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", @@ -998,9 +1007,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.10.33", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.33.tgz", - "integrity": "sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==", + "version": "2.10.34", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.34.tgz", + "integrity": "sha512-IMDedajPifLnHNY0X9n8hKxRTQ6/eTHwr5bDo04WnuqxyKw6LYtQywCuuqPZwhl3aBXMvQpJov42GLCwRRdQzw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -1160,9 +1169,9 @@ "license": "ISC" }, "node_modules/electron-to-chromium": { - "version": "1.5.367", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.367.tgz", - "integrity": "sha512-4Mk/mrynCNQ+atY40D3UpmhLWB6AHMbYMlIrPhHcMF6x0L7O0b052FCAsxw1LlaR++UFuNg3D/A6XCuGDa0guQ==", + "version": "1.5.368", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.368.tgz", + "integrity": "sha512-7RckJJK4uESJF9PxvfMWd3TGqIiieUTG4HxnKaKuIpGbcr+r2ZEB3g2gAhCP3Fqm42vJSzLfgab9eva/C4/XVw==", "dev": true, "license": "ISC" }, @@ -1173,9 +1182,9 @@ "license": "MIT" }, "node_modules/enhanced-resolve": { - "version": "5.22.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.2.tgz", - "integrity": "sha512-0rxICaFZ7NQho/sHely2bvOPRP0Eu2B0NZ9zM54YvRvWMn7jfz3DmnOZDR9LlXDdDcqntAVc6Hfy4gr/tdH/Ag==", + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.23.0.tgz", + "integrity": "sha512-yJN/BOOLxcOW2aQgeif9mSnaUB8KtvmMMp56oA1kx1CRfBKbhZm2pJ+NBY+3eOboHxix8lfjWpHE0Ei5U8RbSA==", "dev": true, "license": "MIT", "dependencies": { @@ -1512,6 +1521,12 @@ "node": ">= 0.4" } }, + "node_modules/howler": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/howler/-/howler-2.2.4.tgz", + "integrity": "sha512-iARIBPgcQrwtEr+tALF+rapJ8qSc+Set2GJQl7xT1MQzWaVkFebdJhR3alVlSiUf5U7nAANKuj3aWpwerocD5w==", + "license": "MIT" + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", diff --git a/frontend/package.json b/frontend/package.json index ff7c7f2..2591681 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,6 +9,7 @@ "preview": "vite preview" }, "dependencies": { + "howler": "^2.2.4", "pixi-live2d-display": "^0.4.0", "pixi.js": "^7.4.3", "react": "^19.2.6", @@ -16,13 +17,14 @@ }, "devDependencies": { "@tailwindcss/vite": "^4.1.6", + "@types/howler": "^2.2.13", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", "autoprefixer": "^10.4.20", "postcss": "^8.5.3", "tailwindcss": "^4.1.6", - "typescript": "~6.0.2", + "typescript": "^6.0.3", "vite": "^8.0.12" } } diff --git a/frontend/public/sounds/alarm.mp3 b/frontend/public/sounds/alarm.mp3 new file mode 100644 index 0000000..29cff71 Binary files /dev/null and b/frontend/public/sounds/alarm.mp3 differ diff --git a/frontend/public/sounds/animals/beehive.mp3 b/frontend/public/sounds/animals/beehive.mp3 new file mode 100644 index 0000000..0ce2c62 Binary files /dev/null and b/frontend/public/sounds/animals/beehive.mp3 differ diff --git a/frontend/public/sounds/animals/birds.mp3 b/frontend/public/sounds/animals/birds.mp3 new file mode 100644 index 0000000..1f21ed6 Binary files /dev/null and b/frontend/public/sounds/animals/birds.mp3 differ diff --git a/frontend/public/sounds/animals/cat-purring.mp3 b/frontend/public/sounds/animals/cat-purring.mp3 new file mode 100644 index 0000000..85bbc39 Binary files /dev/null and b/frontend/public/sounds/animals/cat-purring.mp3 differ diff --git a/frontend/public/sounds/animals/chickens.mp3 b/frontend/public/sounds/animals/chickens.mp3 new file mode 100644 index 0000000..1449b0f Binary files /dev/null and b/frontend/public/sounds/animals/chickens.mp3 differ diff --git a/frontend/public/sounds/animals/cows.mp3 b/frontend/public/sounds/animals/cows.mp3 new file mode 100644 index 0000000..4550bf3 Binary files /dev/null and b/frontend/public/sounds/animals/cows.mp3 differ diff --git a/frontend/public/sounds/animals/crickets.mp3 b/frontend/public/sounds/animals/crickets.mp3 new file mode 100644 index 0000000..3a704cb Binary files /dev/null and b/frontend/public/sounds/animals/crickets.mp3 differ diff --git a/frontend/public/sounds/animals/crows.mp3 b/frontend/public/sounds/animals/crows.mp3 new file mode 100644 index 0000000..172af0f Binary files /dev/null and b/frontend/public/sounds/animals/crows.mp3 differ diff --git a/frontend/public/sounds/animals/dog-barking.mp3 b/frontend/public/sounds/animals/dog-barking.mp3 new file mode 100644 index 0000000..d29dc72 Binary files /dev/null and b/frontend/public/sounds/animals/dog-barking.mp3 differ diff --git a/frontend/public/sounds/animals/frog.mp3 b/frontend/public/sounds/animals/frog.mp3 new file mode 100644 index 0000000..fb8a273 Binary files /dev/null and b/frontend/public/sounds/animals/frog.mp3 differ diff --git a/frontend/public/sounds/animals/horse-gallop.mp3 b/frontend/public/sounds/animals/horse-gallop.mp3 new file mode 100644 index 0000000..852fa4c Binary files /dev/null and b/frontend/public/sounds/animals/horse-gallop.mp3 differ diff --git a/frontend/public/sounds/animals/owl.mp3 b/frontend/public/sounds/animals/owl.mp3 new file mode 100644 index 0000000..175ffd9 Binary files /dev/null and b/frontend/public/sounds/animals/owl.mp3 differ diff --git a/frontend/public/sounds/animals/seagulls.mp3 b/frontend/public/sounds/animals/seagulls.mp3 new file mode 100644 index 0000000..f8a92f5 Binary files /dev/null and b/frontend/public/sounds/animals/seagulls.mp3 differ diff --git a/frontend/public/sounds/animals/sheep.mp3 b/frontend/public/sounds/animals/sheep.mp3 new file mode 100644 index 0000000..ea1cb8c Binary files /dev/null and b/frontend/public/sounds/animals/sheep.mp3 differ diff --git a/frontend/public/sounds/animals/whale.mp3 b/frontend/public/sounds/animals/whale.mp3 new file mode 100644 index 0000000..5bc72ca Binary files /dev/null and b/frontend/public/sounds/animals/whale.mp3 differ diff --git a/frontend/public/sounds/animals/wolf.mp3 b/frontend/public/sounds/animals/wolf.mp3 new file mode 100644 index 0000000..00f4a91 Binary files /dev/null and b/frontend/public/sounds/animals/wolf.mp3 differ diff --git a/frontend/public/sounds/animals/woodpecker.mp3 b/frontend/public/sounds/animals/woodpecker.mp3 new file mode 100644 index 0000000..b8b0508 Binary files /dev/null and b/frontend/public/sounds/animals/woodpecker.mp3 differ diff --git a/frontend/public/sounds/binaural/binaural-alpha.wav b/frontend/public/sounds/binaural/binaural-alpha.wav new file mode 100644 index 0000000..6264a52 Binary files /dev/null and b/frontend/public/sounds/binaural/binaural-alpha.wav differ diff --git a/frontend/public/sounds/binaural/binaural-beta.wav b/frontend/public/sounds/binaural/binaural-beta.wav new file mode 100644 index 0000000..99f8a34 Binary files /dev/null and b/frontend/public/sounds/binaural/binaural-beta.wav differ diff --git a/frontend/public/sounds/binaural/binaural-delta.wav b/frontend/public/sounds/binaural/binaural-delta.wav new file mode 100644 index 0000000..9a7f21e Binary files /dev/null and b/frontend/public/sounds/binaural/binaural-delta.wav differ diff --git a/frontend/public/sounds/binaural/binaural-gamma.wav b/frontend/public/sounds/binaural/binaural-gamma.wav new file mode 100644 index 0000000..cfed717 Binary files /dev/null and b/frontend/public/sounds/binaural/binaural-gamma.wav differ diff --git a/frontend/public/sounds/binaural/binaural-theta.wav b/frontend/public/sounds/binaural/binaural-theta.wav new file mode 100644 index 0000000..ea91512 Binary files /dev/null and b/frontend/public/sounds/binaural/binaural-theta.wav differ diff --git a/frontend/public/sounds/chime.mp3 b/frontend/public/sounds/chime.mp3 new file mode 100644 index 0000000..ca6eee1 Binary files /dev/null and b/frontend/public/sounds/chime.mp3 differ diff --git a/frontend/public/sounds/nature/campfire.mp3 b/frontend/public/sounds/nature/campfire.mp3 new file mode 100644 index 0000000..4cb1731 Binary files /dev/null and b/frontend/public/sounds/nature/campfire.mp3 differ diff --git a/frontend/public/sounds/nature/droplets.mp3 b/frontend/public/sounds/nature/droplets.mp3 new file mode 100644 index 0000000..c14c296 Binary files /dev/null and b/frontend/public/sounds/nature/droplets.mp3 differ diff --git a/frontend/public/sounds/nature/howling-wind.mp3 b/frontend/public/sounds/nature/howling-wind.mp3 new file mode 100644 index 0000000..9c90e16 Binary files /dev/null and b/frontend/public/sounds/nature/howling-wind.mp3 differ diff --git a/frontend/public/sounds/nature/jungle.mp3 b/frontend/public/sounds/nature/jungle.mp3 new file mode 100644 index 0000000..35a3e7e Binary files /dev/null and b/frontend/public/sounds/nature/jungle.mp3 differ diff --git a/frontend/public/sounds/nature/river.mp3 b/frontend/public/sounds/nature/river.mp3 new file mode 100644 index 0000000..31513b5 Binary files /dev/null and b/frontend/public/sounds/nature/river.mp3 differ diff --git a/frontend/public/sounds/nature/walk-in-snow.mp3 b/frontend/public/sounds/nature/walk-in-snow.mp3 new file mode 100644 index 0000000..bc19bda Binary files /dev/null and b/frontend/public/sounds/nature/walk-in-snow.mp3 differ diff --git a/frontend/public/sounds/nature/walk-on-gravel.mp3 b/frontend/public/sounds/nature/walk-on-gravel.mp3 new file mode 100644 index 0000000..c55aca3 Binary files /dev/null and b/frontend/public/sounds/nature/walk-on-gravel.mp3 differ diff --git a/frontend/public/sounds/nature/walk-on-leaves.mp3 b/frontend/public/sounds/nature/walk-on-leaves.mp3 new file mode 100644 index 0000000..b9d427a Binary files /dev/null and b/frontend/public/sounds/nature/walk-on-leaves.mp3 differ diff --git a/frontend/public/sounds/nature/waterfall.mp3 b/frontend/public/sounds/nature/waterfall.mp3 new file mode 100644 index 0000000..ac14211 Binary files /dev/null and b/frontend/public/sounds/nature/waterfall.mp3 differ diff --git a/frontend/public/sounds/nature/waves.mp3 b/frontend/public/sounds/nature/waves.mp3 new file mode 100644 index 0000000..831997f Binary files /dev/null and b/frontend/public/sounds/nature/waves.mp3 differ diff --git a/frontend/public/sounds/nature/wind-in-trees.mp3 b/frontend/public/sounds/nature/wind-in-trees.mp3 new file mode 100644 index 0000000..a25cfab Binary files /dev/null and b/frontend/public/sounds/nature/wind-in-trees.mp3 differ diff --git a/frontend/public/sounds/nature/wind.mp3 b/frontend/public/sounds/nature/wind.mp3 new file mode 100644 index 0000000..572ef55 Binary files /dev/null and b/frontend/public/sounds/nature/wind.mp3 differ diff --git a/frontend/public/sounds/noise/brown-noise.wav b/frontend/public/sounds/noise/brown-noise.wav new file mode 100644 index 0000000..e053a43 Binary files /dev/null and b/frontend/public/sounds/noise/brown-noise.wav differ diff --git a/frontend/public/sounds/noise/pink-noise.wav b/frontend/public/sounds/noise/pink-noise.wav new file mode 100644 index 0000000..2b6c1f7 Binary files /dev/null and b/frontend/public/sounds/noise/pink-noise.wav differ diff --git a/frontend/public/sounds/noise/white-noise.wav b/frontend/public/sounds/noise/white-noise.wav new file mode 100644 index 0000000..e3a0e3d Binary files /dev/null and b/frontend/public/sounds/noise/white-noise.wav differ diff --git a/frontend/public/sounds/places/airport.mp3 b/frontend/public/sounds/places/airport.mp3 new file mode 100644 index 0000000..30f3020 Binary files /dev/null and b/frontend/public/sounds/places/airport.mp3 differ diff --git a/frontend/public/sounds/places/cafe.mp3 b/frontend/public/sounds/places/cafe.mp3 new file mode 100644 index 0000000..27db46d Binary files /dev/null and b/frontend/public/sounds/places/cafe.mp3 differ diff --git a/frontend/public/sounds/places/carousel.mp3 b/frontend/public/sounds/places/carousel.mp3 new file mode 100644 index 0000000..90ca0da Binary files /dev/null and b/frontend/public/sounds/places/carousel.mp3 differ diff --git a/frontend/public/sounds/places/church.mp3 b/frontend/public/sounds/places/church.mp3 new file mode 100644 index 0000000..9bc81e5 Binary files /dev/null and b/frontend/public/sounds/places/church.mp3 differ diff --git a/frontend/public/sounds/places/construction-site.mp3 b/frontend/public/sounds/places/construction-site.mp3 new file mode 100644 index 0000000..ee642a5 Binary files /dev/null and b/frontend/public/sounds/places/construction-site.mp3 differ diff --git a/frontend/public/sounds/places/crowded-bar.mp3 b/frontend/public/sounds/places/crowded-bar.mp3 new file mode 100644 index 0000000..39d299e Binary files /dev/null and b/frontend/public/sounds/places/crowded-bar.mp3 differ diff --git a/frontend/public/sounds/places/laboratory.mp3 b/frontend/public/sounds/places/laboratory.mp3 new file mode 100644 index 0000000..6a65a2a Binary files /dev/null and b/frontend/public/sounds/places/laboratory.mp3 differ diff --git a/frontend/public/sounds/places/laundry-room.mp3 b/frontend/public/sounds/places/laundry-room.mp3 new file mode 100644 index 0000000..49df047 Binary files /dev/null and b/frontend/public/sounds/places/laundry-room.mp3 differ diff --git a/frontend/public/sounds/places/library.mp3 b/frontend/public/sounds/places/library.mp3 new file mode 100644 index 0000000..bdd5690 Binary files /dev/null and b/frontend/public/sounds/places/library.mp3 differ diff --git a/frontend/public/sounds/places/night-village.mp3 b/frontend/public/sounds/places/night-village.mp3 new file mode 100644 index 0000000..8082aeb Binary files /dev/null and b/frontend/public/sounds/places/night-village.mp3 differ diff --git a/frontend/public/sounds/places/office.mp3 b/frontend/public/sounds/places/office.mp3 new file mode 100644 index 0000000..c18f478 Binary files /dev/null and b/frontend/public/sounds/places/office.mp3 differ diff --git a/frontend/public/sounds/places/restaurant.mp3 b/frontend/public/sounds/places/restaurant.mp3 new file mode 100644 index 0000000..0aab6bd Binary files /dev/null and b/frontend/public/sounds/places/restaurant.mp3 differ diff --git a/frontend/public/sounds/places/subway-station.mp3 b/frontend/public/sounds/places/subway-station.mp3 new file mode 100644 index 0000000..57b87f2 Binary files /dev/null and b/frontend/public/sounds/places/subway-station.mp3 differ diff --git a/frontend/public/sounds/places/supermarket.mp3 b/frontend/public/sounds/places/supermarket.mp3 new file mode 100644 index 0000000..9226c9d Binary files /dev/null and b/frontend/public/sounds/places/supermarket.mp3 differ diff --git a/frontend/public/sounds/places/temple.mp3 b/frontend/public/sounds/places/temple.mp3 new file mode 100644 index 0000000..fc1f6f1 Binary files /dev/null and b/frontend/public/sounds/places/temple.mp3 differ diff --git a/frontend/public/sounds/places/underwater.mp3 b/frontend/public/sounds/places/underwater.mp3 new file mode 100644 index 0000000..90c8297 Binary files /dev/null and b/frontend/public/sounds/places/underwater.mp3 differ diff --git a/frontend/public/sounds/rain/heavy-rain.mp3 b/frontend/public/sounds/rain/heavy-rain.mp3 new file mode 100644 index 0000000..d9cfb1f Binary files /dev/null and b/frontend/public/sounds/rain/heavy-rain.mp3 differ diff --git a/frontend/public/sounds/rain/light-rain.mp3 b/frontend/public/sounds/rain/light-rain.mp3 new file mode 100644 index 0000000..91f6cc3 Binary files /dev/null and b/frontend/public/sounds/rain/light-rain.mp3 differ diff --git a/frontend/public/sounds/rain/rain-on-car-roof.mp3 b/frontend/public/sounds/rain/rain-on-car-roof.mp3 new file mode 100644 index 0000000..6082e80 Binary files /dev/null and b/frontend/public/sounds/rain/rain-on-car-roof.mp3 differ diff --git a/frontend/public/sounds/rain/rain-on-leaves.mp3 b/frontend/public/sounds/rain/rain-on-leaves.mp3 new file mode 100644 index 0000000..8318cae Binary files /dev/null and b/frontend/public/sounds/rain/rain-on-leaves.mp3 differ diff --git a/frontend/public/sounds/rain/rain-on-tent.mp3 b/frontend/public/sounds/rain/rain-on-tent.mp3 new file mode 100644 index 0000000..c6ca1a4 Binary files /dev/null and b/frontend/public/sounds/rain/rain-on-tent.mp3 differ diff --git a/frontend/public/sounds/rain/rain-on-umbrella.mp3 b/frontend/public/sounds/rain/rain-on-umbrella.mp3 new file mode 100644 index 0000000..d847ccb Binary files /dev/null and b/frontend/public/sounds/rain/rain-on-umbrella.mp3 differ diff --git a/frontend/public/sounds/rain/rain-on-window.mp3 b/frontend/public/sounds/rain/rain-on-window.mp3 new file mode 100644 index 0000000..babb947 Binary files /dev/null and b/frontend/public/sounds/rain/rain-on-window.mp3 differ diff --git a/frontend/public/sounds/rain/thunder.mp3 b/frontend/public/sounds/rain/thunder.mp3 new file mode 100644 index 0000000..eb9baf7 Binary files /dev/null and b/frontend/public/sounds/rain/thunder.mp3 differ diff --git a/frontend/public/sounds/things/boiling-water.mp3 b/frontend/public/sounds/things/boiling-water.mp3 new file mode 100644 index 0000000..c68accc Binary files /dev/null and b/frontend/public/sounds/things/boiling-water.mp3 differ diff --git a/frontend/public/sounds/things/bubbles.mp3 b/frontend/public/sounds/things/bubbles.mp3 new file mode 100644 index 0000000..8238bbd Binary files /dev/null and b/frontend/public/sounds/things/bubbles.mp3 differ diff --git a/frontend/public/sounds/things/ceiling-fan.mp3 b/frontend/public/sounds/things/ceiling-fan.mp3 new file mode 100644 index 0000000..855f424 Binary files /dev/null and b/frontend/public/sounds/things/ceiling-fan.mp3 differ diff --git a/frontend/public/sounds/things/clock.mp3 b/frontend/public/sounds/things/clock.mp3 new file mode 100644 index 0000000..55641ee Binary files /dev/null and b/frontend/public/sounds/things/clock.mp3 differ diff --git a/frontend/public/sounds/things/dryer.mp3 b/frontend/public/sounds/things/dryer.mp3 new file mode 100644 index 0000000..0dc2f70 Binary files /dev/null and b/frontend/public/sounds/things/dryer.mp3 differ diff --git a/frontend/public/sounds/things/keyboard.mp3 b/frontend/public/sounds/things/keyboard.mp3 new file mode 100644 index 0000000..d417c1a Binary files /dev/null and b/frontend/public/sounds/things/keyboard.mp3 differ diff --git a/frontend/public/sounds/things/morse-code.mp3 b/frontend/public/sounds/things/morse-code.mp3 new file mode 100644 index 0000000..64026d3 Binary files /dev/null and b/frontend/public/sounds/things/morse-code.mp3 differ diff --git a/frontend/public/sounds/things/paper.mp3 b/frontend/public/sounds/things/paper.mp3 new file mode 100644 index 0000000..a0c3775 Binary files /dev/null and b/frontend/public/sounds/things/paper.mp3 differ diff --git a/frontend/public/sounds/things/singing-bowl.mp3 b/frontend/public/sounds/things/singing-bowl.mp3 new file mode 100644 index 0000000..7b7b92c Binary files /dev/null and b/frontend/public/sounds/things/singing-bowl.mp3 differ diff --git a/frontend/public/sounds/things/slide-projector.mp3 b/frontend/public/sounds/things/slide-projector.mp3 new file mode 100644 index 0000000..21e0867 Binary files /dev/null and b/frontend/public/sounds/things/slide-projector.mp3 differ diff --git a/frontend/public/sounds/things/tuning-radio.mp3 b/frontend/public/sounds/things/tuning-radio.mp3 new file mode 100644 index 0000000..1581a29 Binary files /dev/null and b/frontend/public/sounds/things/tuning-radio.mp3 differ diff --git a/frontend/public/sounds/things/typewriter.mp3 b/frontend/public/sounds/things/typewriter.mp3 new file mode 100644 index 0000000..bd3ee8f Binary files /dev/null and b/frontend/public/sounds/things/typewriter.mp3 differ diff --git a/frontend/public/sounds/things/vinyl-effect.mp3 b/frontend/public/sounds/things/vinyl-effect.mp3 new file mode 100644 index 0000000..65abc18 Binary files /dev/null and b/frontend/public/sounds/things/vinyl-effect.mp3 differ diff --git a/frontend/public/sounds/things/washing-machine.mp3 b/frontend/public/sounds/things/washing-machine.mp3 new file mode 100644 index 0000000..edddf31 Binary files /dev/null and b/frontend/public/sounds/things/washing-machine.mp3 differ diff --git a/frontend/public/sounds/things/wind-chimes.mp3 b/frontend/public/sounds/things/wind-chimes.mp3 new file mode 100644 index 0000000..2ea2f6d Binary files /dev/null and b/frontend/public/sounds/things/wind-chimes.mp3 differ diff --git a/frontend/public/sounds/things/windshield-wipers.mp3 b/frontend/public/sounds/things/windshield-wipers.mp3 new file mode 100644 index 0000000..afb57a8 Binary files /dev/null and b/frontend/public/sounds/things/windshield-wipers.mp3 differ diff --git a/frontend/public/sounds/transport/airplane.mp3 b/frontend/public/sounds/transport/airplane.mp3 new file mode 100644 index 0000000..03be198 Binary files /dev/null and b/frontend/public/sounds/transport/airplane.mp3 differ diff --git a/frontend/public/sounds/transport/inside-a-train.mp3 b/frontend/public/sounds/transport/inside-a-train.mp3 new file mode 100644 index 0000000..23d94f4 Binary files /dev/null and b/frontend/public/sounds/transport/inside-a-train.mp3 differ diff --git a/frontend/public/sounds/transport/rowing-boat.mp3 b/frontend/public/sounds/transport/rowing-boat.mp3 new file mode 100644 index 0000000..3ddbccd Binary files /dev/null and b/frontend/public/sounds/transport/rowing-boat.mp3 differ diff --git a/frontend/public/sounds/transport/sailboat.mp3 b/frontend/public/sounds/transport/sailboat.mp3 new file mode 100644 index 0000000..4e42aff Binary files /dev/null and b/frontend/public/sounds/transport/sailboat.mp3 differ diff --git a/frontend/public/sounds/transport/submarine.mp3 b/frontend/public/sounds/transport/submarine.mp3 new file mode 100644 index 0000000..24b8d20 Binary files /dev/null and b/frontend/public/sounds/transport/submarine.mp3 differ diff --git a/frontend/public/sounds/transport/train.mp3 b/frontend/public/sounds/transport/train.mp3 new file mode 100644 index 0000000..46e97cc Binary files /dev/null and b/frontend/public/sounds/transport/train.mp3 differ diff --git a/frontend/public/sounds/urban/ambulance-siren.mp3 b/frontend/public/sounds/urban/ambulance-siren.mp3 new file mode 100644 index 0000000..093c72c Binary files /dev/null and b/frontend/public/sounds/urban/ambulance-siren.mp3 differ diff --git a/frontend/public/sounds/urban/busy-street.mp3 b/frontend/public/sounds/urban/busy-street.mp3 new file mode 100644 index 0000000..67522cf Binary files /dev/null and b/frontend/public/sounds/urban/busy-street.mp3 differ diff --git a/frontend/public/sounds/urban/crowd.mp3 b/frontend/public/sounds/urban/crowd.mp3 new file mode 100644 index 0000000..fd71de7 Binary files /dev/null and b/frontend/public/sounds/urban/crowd.mp3 differ diff --git a/frontend/public/sounds/urban/fireworks.mp3 b/frontend/public/sounds/urban/fireworks.mp3 new file mode 100644 index 0000000..593a737 Binary files /dev/null and b/frontend/public/sounds/urban/fireworks.mp3 differ diff --git a/frontend/public/sounds/urban/highway.mp3 b/frontend/public/sounds/urban/highway.mp3 new file mode 100644 index 0000000..7537c7d Binary files /dev/null and b/frontend/public/sounds/urban/highway.mp3 differ diff --git a/frontend/public/sounds/urban/road.mp3 b/frontend/public/sounds/urban/road.mp3 new file mode 100644 index 0000000..414f153 Binary files /dev/null and b/frontend/public/sounds/urban/road.mp3 differ diff --git a/frontend/public/sounds/urban/traffic.mp3 b/frontend/public/sounds/urban/traffic.mp3 new file mode 100644 index 0000000..ff87d5e Binary files /dev/null and b/frontend/public/sounds/urban/traffic.mp3 differ diff --git a/frontend/src/components/MusicPlayer.tsx b/frontend/src/components/MusicPlayer.tsx index 4dd3c2c..2925da4 100644 --- a/frontend/src/components/MusicPlayer.tsx +++ b/frontend/src/components/MusicPlayer.tsx @@ -17,85 +17,89 @@ export default function MusicPlayer() { const [activeId, setActiveId] = useState('lofi-girl'); const [volume, setVolume] = useState(0.3); const [started, setStarted] = useState(false); - const [playerReady, setPlayerReady] = useState(false); + const [playing, setPlaying] = useState(false); const playerRef = useRef(null); const volumeRef = useRef(volume); const activeIdRef = useRef(activeId); + const readyResolveRef = useRef<(() => void) | null>(null); - // Keep refs in sync so the API callback sees current values useEffect(() => { volumeRef.current = volume; }, [volume]); useEffect(() => { activeIdRef.current = activeId; }, [activeId]); - // Load YouTube IFrame API - const loadAPI = useCallback(() => { - if (document.querySelector('script[src="https://www.youtube.com/iframe_api"]')) { - // Already loaded — just wait for YT to be ready - if ((window as any).YT?.Player) { - createPlayer(); - } - return; - } - - const tag = document.createElement('script'); - tag.src = 'https://www.youtube.com/iframe_api'; - document.head.appendChild(tag); - - (window as any).onYouTubeIframeAPIReady = () => { - createPlayer(); - }; - }, []); - - const createPlayer = useCallback(() => { + // Load YouTube IFrame API and create player + const initPlayer = useCallback(() => { const active = LOFI_PLAYLISTS.find((p) => p.id === activeIdRef.current); if (!active || playerRef.current) return; - playerRef.current = new (window as any).YT.Player('kira-youtube-player', { - height: '1', - width: '1', - videoId: active.videoId, - playerVars: { - autoplay: 1, - controls: 0, - loop: 1, - playlist: active.videoId, - enablejsapi: 1, - origin: window.location.origin, - modestbranding: 1, - fs: 0, - }, - events: { - onReady: (e: any) => { - e.target.setVolume(Math.round(volumeRef.current * 100)); - e.target.playVideo(); - setPlayerReady(true); + const createYT = () => { + playerRef.current = new (window as any).YT.Player('kira-youtube-player', { + height: '1', + width: '1', + videoId: active.videoId, + playerVars: { + autoplay: 1, + controls: 0, + loop: 1, + playlist: active.videoId, + enablejsapi: 1, + modestbranding: 1, + fs: 0, + rel: 0, }, - }, - }); + events: { + onReady: (e: any) => { + e.target.setVolume(Math.round(volumeRef.current * 100)); + e.target.playVideo(); + setPlaying(true); + }, + onStateChange: (e: any) => { + // YT.PlayerState.PLAYING = 1, PAUSED = 2, ENDED = 0 + setPlaying(e.data === 1); + }, + onError: (e: any) => { + console.warn('[MusicPlayer] YouTube error:', e.data); + }, + }, + }); + }; + + if ((window as any).YT?.Player) { + createYT(); + } else { + // Load the script + const tag = document.createElement('script'); + tag.src = 'https://www.youtube.com/iframe_api'; + document.head.appendChild(tag); + (window as any).onYouTubeIframeAPIReady = createYT; + } }, []); const handlePlay = () => { setStarted(true); - loadAPI(); + initPlayer(); }; const changeStation = (id: string) => { setActiveId(id); - if (playerRef.current && playerReady) { + if (playerRef.current && (window as any).YT) { const active = LOFI_PLAYLISTS.find((p) => p.id === id); if (active) { - playerRef.current.loadVideoById(active.videoId); - playerRef.current.setVolume(Math.round(volume * 100)); - playerRef.current.playVideo(); + try { + playerRef.current.loadVideoById(active.videoId); + playerRef.current.setVolume(Math.round(volume * 100)); + } catch {} } } }; // Volume sync useEffect(() => { - if (playerRef.current && playerReady) { - playerRef.current.setVolume(Math.round(volume * 100)); - } - }, [volume, playerReady]); + try { + if (playerRef.current?.setVolume) { + playerRef.current.setVolume(Math.round(volume * 100)); + } + } catch {} + }, [volume]); return (
@@ -134,11 +138,8 @@ export default function MusicPlayer() { ))}
- {/* YouTube player: NOT display:none (API won't init). Offscreen instead. */} -
+ {/* YouTube player: must have real dimensions for the API to work */} +
{!started ? ( @@ -151,7 +152,7 @@ export default function MusicPlayer() { ) : (
- + playing {LOFI_PLAYLISTS.find((p) => p.id === activeId)?.name}
)} diff --git a/frontend/src/components/WhiteNoise.tsx b/frontend/src/components/WhiteNoise.tsx index 0071f84..6ae06fc 100644 --- a/frontend/src/components/WhiteNoise.tsx +++ b/frontend/src/components/WhiteNoise.tsx @@ -1,201 +1,194 @@ -import { useState, useRef, useCallback, useEffect } from 'react'; +import { useState, useRef, useEffect, useCallback } from 'react'; +import { Howl } from 'howler'; -type NoiseType = 'white' | 'pink' | 'brown' | 'rain' | 'cafe'; +interface AmbientSound { + id: string; + label: string; + icon: string; + src: string; +} -const NOISE_PRESETS: { id: NoiseType; label: string; icon: string }[] = [ - { id: 'white', label: 'White', icon: '⚪' }, - { id: 'pink', label: 'Pink', icon: '🌸' }, - { id: 'brown', label: 'Brown', icon: '🤎' }, - { id: 'rain', label: 'Rain', icon: '🌧️' }, - { id: 'cafe', label: 'Cafe', icon: '☕' }, +interface Category { + id: string; + label: string; + icon: string; + sounds: AmbientSound[]; +} + +const CATEGORIES: Category[] = [ + { + id: 'noise', label: 'Noise', icon: '🔉', + sounds: [ + { id: 'white-noise', label: 'White', icon: '⚪', src: '/sounds/noise/white-noise.wav' }, + { id: 'pink-noise', label: 'Pink', icon: '🌸', src: '/sounds/noise/pink-noise.wav' }, + { id: 'brown-noise', label: 'Brown', icon: '🤎', src: '/sounds/noise/brown-noise.wav' }, + ], + }, + { + id: 'rain', label: 'Rain', icon: '🌧️', + sounds: [ + { id: 'light-rain', label: 'Light', icon: '🌦️', src: '/sounds/rain/light-rain.mp3' }, + { id: 'heavy-rain', label: 'Heavy', icon: '⛈️', src: '/sounds/rain/heavy-rain.mp3' }, + { id: 'rain-on-window', label: 'Window', icon: '🪟', src: '/sounds/rain/rain-on-window.mp3' }, + { id: 'thunder', label: 'Thunder', icon: '⚡', src: '/sounds/rain/thunder.mp3' }, + { id: 'rain-on-tent', label: 'Tent', icon: '⛺', src: '/sounds/rain/rain-on-tent.mp3' }, + ], + }, + { + id: 'nature', label: 'Nature', icon: '🌿', + sounds: [ + { id: 'waves', label: 'Waves', icon: '🌊', src: '/sounds/nature/waves.mp3' }, + { id: 'campfire', label: 'Campfire', icon: '🔥', src: '/sounds/nature/campfire.mp3' }, + { id: 'river', label: 'River', icon: '🏞️', src: '/sounds/nature/river.mp3' }, + { id: 'wind', label: 'Wind', icon: '💨', src: '/sounds/nature/wind.mp3' }, + { id: 'jungle', label: 'Jungle', icon: '🌴', src: '/sounds/nature/jungle.mp3' }, + ], + }, + { + id: 'places', label: 'Places', icon: '☕', + sounds: [ + { id: 'cafe', label: 'Cafe', icon: '☕', src: '/sounds/places/cafe.mp3' }, + { id: 'library', label: 'Library', icon: '📚', src: '/sounds/places/library.mp3' }, + { id: 'office', label: 'Office', icon: '🏢', src: '/sounds/places/office.mp3' }, + { id: 'restaurant', label: 'Restaurant', icon: '🍽️', src: '/sounds/places/restaurant.mp3' }, + ], + }, + { + id: 'things', label: 'Things', icon: '🎵', + sounds: [ + { id: 'keyboard', label: 'Keyboard', icon: '⌨️', src: '/sounds/things/keyboard.mp3' }, + { id: 'clock', label: 'Clock', icon: '🕐', src: '/sounds/things/clock.mp3' }, + { id: 'ceiling-fan', label: 'Fan', icon: '🌀', src: '/sounds/things/ceiling-fan.mp3' }, + { id: 'vinyl-effect', label: 'Vinyl', icon: '💿', src: '/sounds/things/vinyl-effect.mp3' }, + { id: 'wind-chimes', label: 'Chimes', icon: '🎐', src: '/sounds/things/wind-chimes.mp3' }, + ], + }, + { + id: 'animals', label: 'Animals', icon: '🐾', + sounds: [ + { id: 'birds', label: 'Birds', icon: '🐦', src: '/sounds/animals/birds.mp3' }, + { id: 'cat-purring', label: 'Cat', icon: '🐱', src: '/sounds/animals/cat-purring.mp3' }, + { id: 'crickets', label: 'Crickets', icon: '🦗', src: '/sounds/animals/crickets.mp3' }, + { id: 'owl', label: 'Owl', icon: '🦉', src: '/sounds/animals/owl.mp3' }, + { id: 'whale', label: 'Whale', icon: '🐋', src: '/sounds/animals/whale.mp3' }, + ], + }, ]; export default function WhiteNoise() { - const [active, setActive] = useState(null); - const [volume, setVolume] = useState(0.25); - const ctxRef = useRef(null); - const gainRef = useRef(null); - const sourceRef = useRef(null); - // For rain/cafe: extra nodes to tear down - const extraNodesRef = useRef([]); + const [activeTab, setActiveTab] = useState('noise'); + const [playing, setPlaying] = useState>({}); // id -> volume 0-1 + const howlsRef = useRef>(new Map()); - const stopNoise = useCallback(() => { - if (sourceRef.current) { - try { sourceRef.current.stop(); } catch {} - sourceRef.current.disconnect(); - sourceRef.current = null; + const activeCategory = CATEGORIES.find((c) => c.id === activeTab) ?? CATEGORIES[0]; + + const toggle = useCallback((sound: AmbientSound) => { + const existing = howlsRef.current.get(sound.id); + if (existing && existing.playing()) { + existing.fade(existing.volume(), 0, 300); + setTimeout(() => { + existing.stop(); + existing.unload(); + howlsRef.current.delete(sound.id); + }, 300); + setPlaying((prev) => { + const next = { ...prev }; + delete next[sound.id]; + return next; + }); + } else { + const howl = new Howl({ + src: [sound.src], + loop: true, + volume: 0.5, + html5: true, + }); + howl.fade(0, 0.5, 300); + howl.play(); + howlsRef.current.set(sound.id, howl); + setPlaying((prev) => ({ ...prev, [sound.id]: 0.5 })); } - extraNodesRef.current.forEach((n) => { try { n.disconnect(); } catch {} }); - extraNodesRef.current = []; - setActive(null); }, []); - const startNoise = useCallback((type: NoiseType) => { - stopNoise(); + const setSoundVolume = useCallback((id: string, vol: number) => { + const howl = howlsRef.current.get(id); + if (howl) howl.volume(vol); + setPlaying((prev) => ({ ...prev, [id]: vol })); + }, []); - const ctx = ctxRef.current || new (window.AudioContext || (window as any).webkitAudioContext)(); - ctxRef.current = ctx; - if (ctx.state === 'suspended') ctx.resume(); - - const sr = ctx.sampleRate; - // 10-second buffer — long enough to avoid obvious loops, short enough to generate fast - const len = 10 * sr; - const buf = ctx.createBuffer(2, len, sr); // stereo for spatial depth - - for (let ch = 0; ch < 2; ch++) { - const d = buf.getChannelData(ch); - if (type === 'white') { - for (let i = 0; i < len; i++) d[i] = Math.random() * 2 - 1; - } else if (type === 'pink') { - // Paul Kellet's pink noise filter (industry standard) - let b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0; - for (let i = 0; i < len; i++) { - const w = Math.random() * 2 - 1; - b0 = 0.99886 * b0 + w * 0.0555179; - b1 = 0.99332 * b1 + w * 0.0750759; - b2 = 0.96900 * b2 + w * 0.1538520; - b3 = 0.86650 * b3 + w * 0.3104856; - b4 = 0.55000 * b4 + w * 0.5329522; - b5 = -0.7616 * b5 - w * 0.0168980; - d[i] = (b0 + b1 + b2 + b3 + b4 + b5 + b6 + w * 0.5362) * 0.11; - b6 = w * 0.115926; - } - } else if (type === 'brown') { - // Brownian motion (integrated white noise) - let last = 0; - for (let i = 0; i < len; i++) { - last += (Math.random() * 2 - 1) * 0.02; - last = Math.max(-1, Math.min(1, last)); // clamp - d[i] = last; - } - } else if (type === 'rain') { - // Layered: low rumble (brown) + random droplet clicks - let last = 0; - for (let i = 0; i < len; i++) { - const w = Math.random() * 2 - 1; - // Brown base for rumble - last += w * 0.005; - last *= 0.998; - // Random droplet pings (sparse impulses filtered) - const drop = Math.random() < 0.0008 ? (Math.random() * 0.6 + 0.2) : 0; - d[i] = last * 0.6 + drop * Math.sin(i * 0.13 + ch) * 0.4; - } - } else if (type === 'cafe') { - // Low brown hum + scattered high transients (clatter) - let last = 0; - for (let i = 0; i < len; i++) { - const w = Math.random() * 2 - 1; - last += w * 0.003; - last *= 0.999; - // Occasional clatter - const clatter = Math.random() < 0.0005 ? (Math.random() * 0.4 + 0.1) * Math.sin(i * 0.47) : 0; - // Distant murmur (band-limited noise burst) - const murmur = Math.random() * 0.02; - d[i] = last * 0.5 + clatter + murmur; - } - } - } - - // Crossfade start/end for seamless loop - const fade = Math.min(sr * 0.05, len / 4); // 50ms fade - for (let i = 0; i < fade; i++) { - const t = i / fade; - for (let ch = 0; ch < 2; ch++) { - const d = buf.getChannelData(ch); - d[i] *= t; // fade in - d[len - 1 - i] *= t; // fade out - } - } - - const src = ctx.createBufferSource(); - src.buffer = buf; - src.loop = true; - - const gain = ctx.createGain(); - gain.gain.value = volume; - - let tail: AudioNode = src; - - // For rain/cafe: add filtering for warmth - if (type === 'rain') { - const lp = ctx.createBiquadFilter(); - lp.type = 'lowpass'; - lp.frequency.value = 6000; - lp.Q.value = 0.5; - tail.connect(lp); - tail = lp; - extraNodesRef.current.push(lp); - } else if (type === 'cafe') { - const bp = ctx.createBiquadFilter(); - bp.type = 'lowpass'; - bp.frequency.value = 3000; - bp.Q.value = 0.8; - tail.connect(bp); - tail = bp; - extraNodesRef.current.push(bp); - } - - tail.connect(gain); - gain.connect(ctx.destination); - src.start(); - - sourceRef.current = src; - gainRef.current = gain; - setActive(type); - }, [volume, stopNoise]); - - const toggle = (type: NoiseType) => { - if (active === type) stopNoise(); - else startNoise(type); - }; - - const changeVolume = (v: number) => { - setVolume(v); - if (gainRef.current) gainRef.current.gain.value = v; - }; - - // Cleanup on unmount - useEffect(() => () => { - stopNoise(); - ctxRef.current?.close().catch(() => {}); - }, [stopNoise]); + // Cleanup all on unmount + useEffect(() => { + return () => { + howlsRef.current.forEach((h) => { try { h.stop(); h.unload(); } catch {} }); + howlsRef.current.clear(); + }; + }, []); return (

- 🌬️ White Noise + 🌬️ Ambient

-
- {NOISE_PRESETS.map((p) => ( + + {/* Category tabs */} +
+ {CATEGORIES.map((cat) => ( ))}
-
- Vol - changeVolume(parseFloat(e.target.value))} - className="flex-1 accent-kira-pink" - /> - {Math.round(volume * 100)}% + + {/* Sound grid */} +
+ {activeCategory.sounds.map((sound) => { + const vol = playing[sound.id]; + const isActive = vol !== undefined; + return ( +
+ + + {sound.label} + + {isActive && ( + setSoundVolume(sound.id, parseFloat(e.target.value))} + className="flex-1 accent-kira-pink" + /> + )} +
+ ); + })}
- {active && ( -
Playing {active} noise — body double approved ✨
+ + {/* Active sounds count */} + {Object.keys(playing).length > 0 && ( +
+ {Object.keys(playing).length} sound{Object.keys(playing).length > 1 ? 's' : ''} mixing ✨ +
)}
);