diff --git a/apps/editor/public/audios/sfx/item_delete.mp3 b/apps/editor/public/audios/sfx/item_delete.mp3 index 2bd0ad89..bf56a2cf 100644 Binary files a/apps/editor/public/audios/sfx/item_delete.mp3 and b/apps/editor/public/audios/sfx/item_delete.mp3 differ diff --git a/apps/editor/public/audios/sfx/structure_delete.mp3 b/apps/editor/public/audios/sfx/structure_delete.mp3 index b0b5d9f6..5186219e 100644 Binary files a/apps/editor/public/audios/sfx/structure_delete.mp3 and b/apps/editor/public/audios/sfx/structure_delete.mp3 differ diff --git a/packages/editor/src/components/editor/floating-action-menu.tsx b/packages/editor/src/components/editor/floating-action-menu.tsx index 0b43110e..e5a74395 100644 --- a/packages/editor/src/components/editor/floating-action-menu.tsx +++ b/packages/editor/src/components/editor/floating-action-menu.tsx @@ -33,7 +33,7 @@ import { useFrame } from '@react-three/fiber' import { useCallback, useRef } from 'react' import * as THREE from 'three' import { duplicateRoofSubtree } from '../../lib/roof-duplication' -import { sfxEmitter } from '../../lib/sfx-bus' +import { emitDeleteSFX, sfxEmitter } from '../../lib/sfx-bus' import { duplicateStairSubtree } from '../../lib/stair-duplication' import useEditor from '../../store/use-editor' import { formatMeasurement, MeasurementPill } from './measurement-pill' @@ -514,11 +514,7 @@ export function FloatingActionMenu() { (e: React.MouseEvent) => { e.stopPropagation() if (!selectedId) return - if (node?.type === 'item') { - sfxEmitter.emit('sfx:item-delete') - } else { - sfxEmitter.emit('sfx:structure-delete') - } + emitDeleteSFX(node?.type) setSelection({ selectedIds: [] }) useScene.getState().deleteNode(selectedId as AnyNodeId) }, diff --git a/packages/editor/src/components/editor/selection-manager.tsx b/packages/editor/src/components/editor/selection-manager.tsx index 83758d55..f7811948 100644 --- a/packages/editor/src/components/editor/selection-manager.tsx +++ b/packages/editor/src/components/editor/selection-manager.tsx @@ -50,7 +50,7 @@ import { hasActivePaintMaterial, resolveActivePaintMaterialFromSelection, } from '../../lib/material-paint' -import { sfxEmitter } from '../../lib/sfx-bus' +import { emitDeleteSFX } from '../../lib/sfx-bus' import useEditor, { type MaterialTargetRole, type Phase, @@ -1555,11 +1555,7 @@ export const SelectionManager = () => { event.stopPropagation() // Play appropriate SFX - if (node.type === 'item') { - sfxEmitter.emit('sfx:item-delete') - } else { - sfxEmitter.emit('sfx:structure-delete') - } + emitDeleteSFX(node.type) useScene.getState().deleteNode(node.id as AnyNodeId) if (node.parentId) useScene.getState().dirtyNodes.add(node.parentId as AnyNodeId) diff --git a/packages/editor/src/hooks/use-keyboard.ts b/packages/editor/src/hooks/use-keyboard.ts index eeba55cc..3fd7997d 100644 --- a/packages/editor/src/hooks/use-keyboard.ts +++ b/packages/editor/src/hooks/use-keyboard.ts @@ -7,7 +7,7 @@ import { copySelectedNodesToEditorClipboard, pasteEditorClipboardToLevel, } from '../lib/scene-clipboard' -import { sfxEmitter } from '../lib/sfx-bus' +import { emitDeleteSFX, sfxEmitter } from '../lib/sfx-bus' import { toggleWindowOpenState } from '../lib/window-interaction' import useEditor from '../store/use-editor' @@ -322,11 +322,7 @@ export const useKeyboard = ({ // Play appropriate SFX based on what's being deleted if (selectedNodeIds.length === 1) { const node = useScene.getState().nodes[selectedNodeIds[0]!] - if (node?.type === 'item') { - sfxEmitter.emit('sfx:item-delete') - } else { - sfxEmitter.emit('sfx:structure-delete') - } + emitDeleteSFX(node?.type) } else { sfxEmitter.emit('sfx:structure-delete') } diff --git a/packages/editor/src/lib/sfx-bus.ts b/packages/editor/src/lib/sfx-bus.ts index 109cb539..ff555612 100644 --- a/packages/editor/src/lib/sfx-bus.ts +++ b/packages/editor/src/lib/sfx-bus.ts @@ -55,3 +55,19 @@ export function initSFXBus() { export function triggerSFX(event: keyof SFXEvents) { sfxEmitter.emit(event) } + +/** + * Node types whose deletion should use the lighter item-delete cue rather + * than the heavier structure-delete one. Shelves are furniture-like placeable + * objects, so they sound like items being removed, not structures demolished. + */ +const ITEM_DELETE_NODE_TYPES = new Set(['item', 'shelf']) + +/** + * Emit the delete SFX appropriate for a deleted node's type. + */ +export function emitDeleteSFX(nodeType: string | undefined) { + sfxEmitter.emit( + nodeType && ITEM_DELETE_NODE_TYPES.has(nodeType) ? 'sfx:item-delete' : 'sfx:structure-delete', + ) +} diff --git a/packages/editor/src/lib/sfx-player.ts b/packages/editor/src/lib/sfx-player.ts index a510642d..5106c7c7 100644 --- a/packages/editor/src/lib/sfx-player.ts +++ b/packages/editor/src/lib/sfx-player.ts @@ -39,7 +39,7 @@ export const SFX: Record = { src: '/audios/sfx/item_delete.mp3', rateRange: [0.9, 1.1], volumeRange: [0.9, 1.0], - panJitter: 0.15, + panJitter: 0.05, }, itemPick: { src: '/audios/sfx/item_pick.mp3', @@ -77,7 +77,7 @@ export const SFX: Record = { src: '/audios/sfx/structure_delete.mp3', rateRange: [0.9, 1.1], volumeRange: [0.9, 1.0], - panJitter: 0.15, + panJitter: 0.08, }, snapshotCapture: { // Shutter should sound consistent — no variation.