feat(audio): volume в проекте, DnD, параллельные плейлисты

Громкость треков сцены/игры сохраняется в проекте; порядок через DnD; несколько плейлистов сразу; автоимя из файла; стоп превью при запуске сессии.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ivan Fontosh
2026-09-05 17:09:26 +08:00
parent dbe8ab1fda
commit 586166cacd
20 changed files with 640 additions and 239 deletions
+21
View File
@@ -110,8 +110,29 @@ export type SceneAudioRef = {
assetId: AssetId;
autoplay: boolean;
loop: boolean;
/** Громкость 0…1; дефолт на пульте при старте сессии. */
volume: number;
};
export function clampSceneAudioVolume(v: unknown): number {
if (typeof v !== 'number' || !Number.isFinite(v)) return 1;
return Math.max(0, Math.min(1, v));
}
export function normalizeSceneAudioRef(raw: {
assetId: AssetId;
autoplay?: boolean;
loop?: boolean;
volume?: unknown;
}): SceneAudioRef {
return {
assetId: raw.assetId,
autoplay: Boolean(raw.autoplay),
loop: Boolean(raw.loop),
volume: clampSceneAudioVolume(raw.volume),
};
}
export type SceneMediaRefs = {
videos: AssetId[];
audios: SceneAudioRef[];
+29
View File
@@ -0,0 +1,29 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import { clampSceneAudioVolume, normalizeSceneAudioRef } from '../../shared/types/domain';
import type { AssetId } from '../../shared/types/ids';
void test('clampSceneAudioVolume clamps to 0…1', () => {
assert.equal(clampSceneAudioVolume(0.5), 0.5);
assert.equal(clampSceneAudioVolume(-1), 0);
assert.equal(clampSceneAudioVolume(2), 1);
assert.equal(clampSceneAudioVolume(undefined), 1);
assert.equal(clampSceneAudioVolume(NaN), 1);
});
void test('normalizeSceneAudioRef defaults volume to 1', () => {
const id = 'a1' as AssetId;
assert.deepEqual(normalizeSceneAudioRef({ assetId: id, autoplay: true, loop: false }), {
assetId: id,
autoplay: true,
loop: false,
volume: 1,
});
assert.deepEqual(normalizeSceneAudioRef({ assetId: id, autoplay: false, loop: true, volume: 0.25 }), {
assetId: id,
autoplay: false,
loop: true,
volume: 0.25,
});
});