7 Commits

Author SHA1 Message Date
1bd8aa0fea cringe sfx
All checks were successful
Deploy / publish-web (push) Successful in 51s
2026-02-06 23:14:13 +06:00
626f52c616 cringe sfx
All checks were successful
Deploy / publish-web (push) Successful in 50s
2026-02-06 23:06:50 +06:00
29914d73a0 cringe sfx 2026-02-06 23:06:42 +06:00
dd530266f9 cringe sfx
All checks were successful
Deploy / publish-web (push) Successful in 49s
2026-02-06 22:44:11 +06:00
a37b2048fe cringe sfx
All checks were successful
Deploy / publish-web (push) Successful in 53s
2026-02-06 22:41:58 +06:00
e3ac3e003c cringe sfx
All checks were successful
Deploy / publish-web (push) Successful in 2m35s
2026-02-06 22:32:01 +06:00
6fa142f133 productName typo 2026-02-03 22:06:09 +06:00
214 changed files with 126 additions and 4 deletions

Binary file not shown.

View File

@@ -8,6 +8,7 @@ export const useApp = createGlobalState(() => {
const mediasoup = useMediasoup() const mediasoup = useMediasoup()
const signaling = useSignaling() const signaling = useSignaling()
const toast = useToast() const toast = useToast()
const sfx = useSfx()
const ready = ref(false) const ready = ref(false)
const isTauri = computed(() => '__TAURI_INTERNALS__' in window) const isTauri = computed(() => '__TAURI_INTERNALS__' in window)
@@ -52,6 +53,7 @@ export const useApp = createGlobalState(() => {
await mediasoup.pauseProducer(mediasoup.micProducer.value) await mediasoup.pauseProducer(mediasoup.micProducer.value)
sfx.playEvent('mic-off').then()
toast.add({ severity: 'info', summary: 'Microphone muted', closable: false, life: 1000 }) toast.add({ severity: 'info', summary: 'Microphone muted', closable: false, life: 1000 })
} }
@@ -65,6 +67,7 @@ export const useApp = createGlobalState(() => {
await mediasoup.resumeProducer(mediasoup.micProducer.value) await mediasoup.resumeProducer(mediasoup.micProducer.value)
sfx.playEvent('mic-on').then()
toast.add({ severity: 'info', summary: 'Microphone activated', closable: false, life: 1000 }) toast.add({ severity: 'info', summary: 'Microphone activated', closable: false, life: 1000 })
} }
@@ -115,18 +118,22 @@ export const useApp = createGlobalState(() => {
async function toggleVideo() { async function toggleVideo() {
if (!mediasoup.videoProducer.value) { if (!mediasoup.videoProducer.value) {
await mediasoup.enableVideo() await mediasoup.enableVideo()
await sfx.playEvent('stream-on')
} }
else { else {
await mediasoup.disableProducer(mediasoup.videoProducer.value) await mediasoup.disableProducer(mediasoup.videoProducer.value)
await sfx.playEvent('stream-off')
} }
} }
async function toggleShare() { async function toggleShare() {
if (!mediasoup.shareProducer.value) { if (!mediasoup.shareProducer.value) {
await mediasoup.enableShare() await mediasoup.enableShare()
await sfx.playEvent('stream-on')
} }
else { else {
await mediasoup.disableProducer(mediasoup.shareProducer.value) await mediasoup.disableProducer(mediasoup.shareProducer.value)
await sfx.playEvent('stream-off')
} }
} }

View File

@@ -29,9 +29,10 @@ const ICE_SERVERS: RTCIceServer[] = [
export const useMediasoup = createSharedComposable(() => { export const useMediasoup = createSharedComposable(() => {
const toast = useToast() const toast = useToast()
const sfx = useSfx()
const signaling = useSignaling() const signaling = useSignaling()
const { addClient, removeClient } = useClients() const { addClient, removeClient, me } = useClients()
const preferences = usePreferences() const preferences = usePreferences()
const { getShareStream } = useDevices() const { getShareStream } = useDevices()
@@ -169,12 +170,16 @@ export const useMediasoup = createSharedComposable(() => {
addClient(...joinedClients) addClient(...joinedClients)
if (me.value)
sfx.playRandomConnectionSound(me.value.socketId).then()
toast.add({ severity: 'success', summary: 'Joined', closable: false, life: 1000 }) toast.add({ severity: 'success', summary: 'Joined', closable: false, life: 1000 })
await enableMic() await enableMic()
}) })
socket.on('newPeer', (client) => { socket.on('newPeer', (client) => {
sfx.playRandomConnectionSound(client.socketId).then()
addClient(client) addClient(client)
}) })
@@ -200,6 +205,9 @@ export const useMediasoup = createSharedComposable(() => {
appData: { ...appData, socketId }, appData: { ...appData, socketId },
}) })
if (kind === 'video')
sfx.playEvent('stream-on').then()
if (producerPaused) if (producerPaused)
consumer.pause() consumer.pause()
@@ -219,6 +227,9 @@ export const useMediasoup = createSharedComposable(() => {
}) })
consumer.observer.on('close', () => { consumer.observer.on('close', () => {
if (kind === 'video')
sfx.playEvent('stream-off').then()
delete consumers.value[consumer.id] delete consumers.value[consumer.id]
}) })

View File

@@ -0,0 +1,86 @@
import { createSharedComposable } from '@vueuse/core'
import { Howl } from 'howler'
const CONNECTION_SOUNDS = Object.keys(import.meta.glob('@/../public/sfx/connection/*.ogg')).map(path => path.replace('../public', ''))
console.log('CONNECTION_SOUNDS', CONNECTION_SOUNDS)
function hashStringToNumber(str: string, cap: number): number {
let hash = 0
for (let i = 0; i < str.length; i++) {
hash = (hash * 31 + str.charCodeAt(i)) | 0
}
return Math.abs(hash) % cap
}
const oneShots: Howl[] = []
type SfxEvent = 'mic-on' | 'mic-off' | 'stream-on' | 'stream-off' | 'connection'
const EVENT_VOLUME: Record<SfxEvent, number> = {
'mic-on': 0.2,
'mic-off': 0.2,
'stream-on': 0.03,
'stream-off': 0.03,
'connection': 0.1,
}
export const useSfx = createSharedComposable(() => {
async function play(src: string, volume = 0.2): Promise<void> {
return new Promise((resolve) => {
const howl = new Howl({
src,
autoplay: true,
loop: false,
volume,
})
howl.on('end', () => {
resolve()
})
})
}
async function playOneShot(src: string, volume = 0.2): Promise<void> {
for (const oneShot of oneShots) {
oneShot.stop()
}
oneShots.length = 0
return new Promise((resolve) => {
const howl = new Howl({
src,
autoplay: true,
loop: false,
volume,
})
oneShots.push(howl)
howl.on('end', () => {
resolve()
})
})
}
async function playEvent(event: SfxEvent) {
switch (event) {
default:
await playOneShot(`/sfx/${event}.ogg`, EVENT_VOLUME[event])
break
}
}
async function playRandomConnectionSound(seed: string) {
await playEvent('stream-on')
await play(CONNECTION_SOUNDS[hashStringToNumber(seed, CONNECTION_SOUNDS.length)]!, 0.1)
}
return {
playOneShot,
play,
playRandomConnectionSound,
playEvent,
}
})

View File

@@ -19,6 +19,7 @@
"@tauri-apps/plugin-updater": "~2", "@tauri-apps/plugin-updater": "~2",
"@vueuse/core": "^13.9.0", "@vueuse/core": "^13.9.0",
"hotkeys-js": "^4.0.0", "hotkeys-js": "^4.0.0",
"howler": "^2.2.4",
"lucide-vue-next": "^0.562.0", "lucide-vue-next": "^0.562.0",
"mediasoup-client": "^3.18.6", "mediasoup-client": "^3.18.6",
"nuxt": "^4.2.2", "nuxt": "^4.2.2",
@@ -37,6 +38,7 @@
"@antfu/eslint-config": "^5.4.1", "@antfu/eslint-config": "^5.4.1",
"@primevue/nuxt-module": "^4.4.0", "@primevue/nuxt-module": "^4.4.0",
"@tauri-apps/cli": "^2.8.4", "@tauri-apps/cli": "^2.8.4",
"@types/howler": "^2",
"eslint": "^9.36.0", "eslint": "^9.36.0",
"eslint-plugin-format": "^1.0.2", "eslint-plugin-format": "^1.0.2",
"sass-embedded": "^1.93.2", "sass-embedded": "^1.93.2",

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More