mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-01 19:42:03 +00:00
feat: add @hyperframes/sfx package with typed SFX catalog
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
61c5257402
commit
740878764c
@@ -11,9 +11,15 @@ const config: KnipConfig = {
|
||||
"packages/engine": {
|
||||
entry: ["src/index.ts"],
|
||||
},
|
||||
"packages/fonts": {
|
||||
entry: ["src/index.ts", "src/catalog.ts"],
|
||||
},
|
||||
"packages/producer": {
|
||||
entry: ["src/index.ts", "src/server.ts"],
|
||||
},
|
||||
"packages/sfx": {
|
||||
entry: ["src/index.ts"],
|
||||
},
|
||||
"packages/studio": {
|
||||
entry: ["src/index.ts", "src/styles/tailwind-preset.ts"],
|
||||
},
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"name": "@hyperframes/sfx",
|
||||
"version": "0.1.2",
|
||||
"description": "Typed catalog of CC0 sound effects for hyperframes agents",
|
||||
"type": "module",
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./src/index.ts",
|
||||
"types": "./src/index.ts"
|
||||
},
|
||||
"./transitions": {
|
||||
"import": "./src/transitions.ts",
|
||||
"types": "./src/transitions.ts"
|
||||
},
|
||||
"./ui": {
|
||||
"import": "./src/ui.ts",
|
||||
"types": "./src/ui.ts"
|
||||
},
|
||||
"./cinematic": {
|
||||
"import": "./src/cinematic.ts",
|
||||
"types": "./src/cinematic.ts"
|
||||
},
|
||||
"./ambient": {
|
||||
"import": "./src/ambient.ts",
|
||||
"types": "./src/ambient.ts"
|
||||
},
|
||||
"./musical": {
|
||||
"import": "./src/musical.ts",
|
||||
"types": "./src/musical.ts"
|
||||
}
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts"
|
||||
},
|
||||
"./transitions": {
|
||||
"import": "./dist/transitions.js",
|
||||
"types": "./dist/transitions.d.ts"
|
||||
},
|
||||
"./ui": {
|
||||
"import": "./dist/ui.js",
|
||||
"types": "./dist/ui.d.ts"
|
||||
},
|
||||
"./cinematic": {
|
||||
"import": "./dist/cinematic.js",
|
||||
"types": "./dist/cinematic.d.ts"
|
||||
},
|
||||
"./ambient": {
|
||||
"import": "./dist/ambient.js",
|
||||
"types": "./dist/ambient.d.ts"
|
||||
},
|
||||
"./musical": {
|
||||
"import": "./dist/musical.js",
|
||||
"types": "./dist/musical.d.ts"
|
||||
}
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "vitest run"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tsx": "^4.21.0",
|
||||
"typescript": "^5.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
import { SFX_BASE_URL } from './constants.js';
|
||||
import type { SfxEntry } from './types.js';
|
||||
|
||||
export const applause: SfxEntry = {
|
||||
name: 'applause',
|
||||
category: 'ambient',
|
||||
url: `${SFX_BASE_URL}/ambient/applause.mp3`,
|
||||
duration: 3.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['clapping', 'crowd', 'celebration'],
|
||||
};
|
||||
|
||||
export const crowdCheer: SfxEntry = {
|
||||
name: 'crowdCheer',
|
||||
category: 'ambient',
|
||||
url: `${SFX_BASE_URL}/ambient/crowdCheer.mp3`,
|
||||
duration: 3.5,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['cheering', 'excitement', 'crowd'],
|
||||
};
|
||||
|
||||
export const typingKeyboard: SfxEntry = {
|
||||
name: 'typingKeyboard',
|
||||
category: 'ambient',
|
||||
url: `${SFX_BASE_URL}/ambient/typingKeyboard.mp3`,
|
||||
duration: 5.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['keyboard', 'office', 'work'],
|
||||
};
|
||||
|
||||
export const windGentle: SfxEntry = {
|
||||
name: 'windGentle',
|
||||
category: 'ambient',
|
||||
url: `${SFX_BASE_URL}/ambient/windGentle.mp3`,
|
||||
duration: 8.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['breeze', 'nature', 'calm'],
|
||||
};
|
||||
|
||||
export const rainLight: SfxEntry = {
|
||||
name: 'rainLight',
|
||||
category: 'ambient',
|
||||
url: `${SFX_BASE_URL}/ambient/rainLight.mp3`,
|
||||
duration: 10.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['rain', 'drizzle', 'relaxing'],
|
||||
};
|
||||
|
||||
export const oceanWaves: SfxEntry = {
|
||||
name: 'oceanWaves',
|
||||
category: 'ambient',
|
||||
url: `${SFX_BASE_URL}/ambient/oceanWaves.mp3`,
|
||||
duration: 10.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['sea', 'waves', 'beach'],
|
||||
};
|
||||
|
||||
export const birds: SfxEntry = {
|
||||
name: 'birds',
|
||||
category: 'ambient',
|
||||
url: `${SFX_BASE_URL}/ambient/birds.mp3`,
|
||||
duration: 8.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['chirping', 'nature', 'morning'],
|
||||
};
|
||||
|
||||
export const cityTraffic: SfxEntry = {
|
||||
name: 'cityTraffic',
|
||||
category: 'ambient',
|
||||
url: `${SFX_BASE_URL}/ambient/cityTraffic.mp3`,
|
||||
duration: 10.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['urban', 'cars', 'street'],
|
||||
};
|
||||
|
||||
export const cafeMurmur: SfxEntry = {
|
||||
name: 'cafeMurmur',
|
||||
category: 'ambient',
|
||||
url: `${SFX_BASE_URL}/ambient/cafeMurmur.mp3`,
|
||||
duration: 10.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['coffee', 'chatter', 'cozy'],
|
||||
};
|
||||
|
||||
export const fireCrackle: SfxEntry = {
|
||||
name: 'fireCrackle',
|
||||
category: 'ambient',
|
||||
url: `${SFX_BASE_URL}/ambient/fireCrackle.mp3`,
|
||||
duration: 10.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['fireplace', 'warm', 'crackling'],
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
import * as transitions from './transitions.js';
|
||||
import * as ui from './ui.js';
|
||||
import * as cinematic from './cinematic.js';
|
||||
import * as ambient from './ambient.js';
|
||||
import * as musical from './musical.js';
|
||||
import type { SfxEntry, SfxCategory } from './types.js';
|
||||
|
||||
export const catalog: readonly SfxEntry[] = [
|
||||
...Object.values(transitions),
|
||||
...Object.values(ui),
|
||||
...Object.values(cinematic),
|
||||
...Object.values(ambient),
|
||||
...Object.values(musical),
|
||||
];
|
||||
|
||||
export function findSfx(name: string): SfxEntry | undefined {
|
||||
return catalog.find((s) => s.name === name);
|
||||
}
|
||||
|
||||
export function findSfxByCategory(category: SfxCategory): readonly SfxEntry[] {
|
||||
return catalog.filter((s) => s.category === category);
|
||||
}
|
||||
|
||||
export function resolveSfxUrl(name: string): string | undefined {
|
||||
return findSfx(name)?.url;
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
import { SFX_BASE_URL } from './constants.js';
|
||||
import type { SfxEntry } from './types.js';
|
||||
|
||||
export const impactHeavy: SfxEntry = {
|
||||
name: 'impactHeavy',
|
||||
category: 'cinematic',
|
||||
url: `${SFX_BASE_URL}/cinematic/impactHeavy.mp3`,
|
||||
duration: 1.5,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['heavy', 'dramatic', 'hit'],
|
||||
};
|
||||
|
||||
export const impactLight: SfxEntry = {
|
||||
name: 'impactLight',
|
||||
category: 'cinematic',
|
||||
url: `${SFX_BASE_URL}/cinematic/impactLight.mp3`,
|
||||
duration: 0.8,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['light', 'subtle', 'tap'],
|
||||
};
|
||||
|
||||
export const riserSlow: SfxEntry = {
|
||||
name: 'riserSlow',
|
||||
category: 'cinematic',
|
||||
url: `${SFX_BASE_URL}/cinematic/riserSlow.mp3`,
|
||||
duration: 3.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['buildup', 'tension', 'ascending'],
|
||||
};
|
||||
|
||||
export const riserFast: SfxEntry = {
|
||||
name: 'riserFast',
|
||||
category: 'cinematic',
|
||||
url: `${SFX_BASE_URL}/cinematic/riserFast.mp3`,
|
||||
duration: 1.5,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['buildup', 'quick', 'ascending'],
|
||||
};
|
||||
|
||||
export const hit: SfxEntry = {
|
||||
name: 'hit',
|
||||
category: 'cinematic',
|
||||
url: `${SFX_BASE_URL}/cinematic/hit.mp3`,
|
||||
duration: 0.6,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['impact', 'punch', 'accent'],
|
||||
};
|
||||
|
||||
export const boom: SfxEntry = {
|
||||
name: 'boom',
|
||||
category: 'cinematic',
|
||||
url: `${SFX_BASE_URL}/cinematic/boom.mp3`,
|
||||
duration: 2.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['explosion', 'deep', 'rumble'],
|
||||
};
|
||||
|
||||
export const drumRoll: SfxEntry = {
|
||||
name: 'drumRoll',
|
||||
category: 'cinematic',
|
||||
url: `${SFX_BASE_URL}/cinematic/drumRoll.mp3`,
|
||||
duration: 3.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['anticipation', 'buildup', 'percussion'],
|
||||
};
|
||||
|
||||
export const tensionBuild: SfxEntry = {
|
||||
name: 'tensionBuild',
|
||||
category: 'cinematic',
|
||||
url: `${SFX_BASE_URL}/cinematic/tensionBuild.mp3`,
|
||||
duration: 4.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['suspense', 'rising', 'dramatic'],
|
||||
};
|
||||
|
||||
export const reveal: SfxEntry = {
|
||||
name: 'reveal',
|
||||
category: 'cinematic',
|
||||
url: `${SFX_BASE_URL}/cinematic/reveal.mp3`,
|
||||
duration: 1.5,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['unveil', 'surprise', 'magical'],
|
||||
};
|
||||
|
||||
export const stinger: SfxEntry = {
|
||||
name: 'stinger',
|
||||
category: 'cinematic',
|
||||
url: `${SFX_BASE_URL}/cinematic/stinger.mp3`,
|
||||
duration: 1.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['accent', 'sharp', 'dramatic'],
|
||||
};
|
||||
|
||||
export const shimmer: SfxEntry = {
|
||||
name: 'shimmer',
|
||||
category: 'cinematic',
|
||||
url: `${SFX_BASE_URL}/cinematic/shimmer.mp3`,
|
||||
duration: 1.2,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['sparkle', 'ethereal', 'bright'],
|
||||
};
|
||||
|
||||
export const deepBass: SfxEntry = {
|
||||
name: 'deepBass',
|
||||
category: 'cinematic',
|
||||
url: `${SFX_BASE_URL}/cinematic/deepBass.mp3`,
|
||||
duration: 2.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['low', 'sub', 'rumble'],
|
||||
};
|
||||
|
||||
export const epicWhoosh: SfxEntry = {
|
||||
name: 'epicWhoosh',
|
||||
category: 'cinematic',
|
||||
url: `${SFX_BASE_URL}/cinematic/epicWhoosh.mp3`,
|
||||
duration: 1.5,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['grand', 'sweep', 'movement'],
|
||||
};
|
||||
|
||||
export const brassHit: SfxEntry = {
|
||||
name: 'brassHit',
|
||||
category: 'cinematic',
|
||||
url: `${SFX_BASE_URL}/cinematic/brassHit.mp3`,
|
||||
duration: 1.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['horn', 'powerful', 'accent'],
|
||||
};
|
||||
|
||||
export const orchestraHit: SfxEntry = {
|
||||
name: 'orchestraHit',
|
||||
category: 'cinematic',
|
||||
url: `${SFX_BASE_URL}/cinematic/orchestraHit.mp3`,
|
||||
duration: 1.2,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['orchestra', 'full', 'dramatic'],
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
// Base URL for SFX assets. Uses jsdelivr CDN which auto-serves npm package files.
|
||||
// Override with SFX_BASE_URL env var for self-hosted setups.
|
||||
export const SFX_BASE_URL =
|
||||
process.env.SFX_BASE_URL ?? 'https://cdn.jsdelivr.net/npm/@hyperframes/sfx@0.1.2/assets';
|
||||
@@ -0,0 +1,8 @@
|
||||
export type { SfxEntry, SfxCategory } from './types.js';
|
||||
export { catalog, findSfx, findSfxByCategory, resolveSfxUrl } from './catalog.js';
|
||||
export { SFX_BASE_URL } from './constants.js';
|
||||
export * as transitions from './transitions.js';
|
||||
export * as ui from './ui.js';
|
||||
export * as cinematic from './cinematic.js';
|
||||
export * as ambient from './ambient.js';
|
||||
export * as musical from './musical.js';
|
||||
@@ -0,0 +1,102 @@
|
||||
import { SFX_BASE_URL } from './constants.js';
|
||||
import type { SfxEntry } from './types.js';
|
||||
|
||||
export const pianoChord: SfxEntry = {
|
||||
name: 'pianoChord',
|
||||
category: 'musical',
|
||||
url: `${SFX_BASE_URL}/musical/pianoChord.mp3`,
|
||||
duration: 2.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['piano', 'chord', 'elegant'],
|
||||
};
|
||||
|
||||
export const guitarStrum: SfxEntry = {
|
||||
name: 'guitarStrum',
|
||||
category: 'musical',
|
||||
url: `${SFX_BASE_URL}/musical/guitarStrum.mp3`,
|
||||
duration: 1.5,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['guitar', 'acoustic', 'strum'],
|
||||
};
|
||||
|
||||
export const bellChime: SfxEntry = {
|
||||
name: 'bellChime',
|
||||
category: 'musical',
|
||||
url: `${SFX_BASE_URL}/musical/bellChime.mp3`,
|
||||
duration: 2.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['bell', 'chime', 'bright'],
|
||||
};
|
||||
|
||||
export const harpGliss: SfxEntry = {
|
||||
name: 'harpGliss',
|
||||
category: 'musical',
|
||||
url: `${SFX_BASE_URL}/musical/harpGliss.mp3`,
|
||||
duration: 2.5,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['harp', 'glissando', 'dreamy'],
|
||||
};
|
||||
|
||||
export const synthPad: SfxEntry = {
|
||||
name: 'synthPad',
|
||||
category: 'musical',
|
||||
url: `${SFX_BASE_URL}/musical/synthPad.mp3`,
|
||||
duration: 4.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['synth', 'pad', 'atmospheric'],
|
||||
};
|
||||
|
||||
export const bassDrop: SfxEntry = {
|
||||
name: 'bassDrop',
|
||||
category: 'musical',
|
||||
url: `${SFX_BASE_URL}/musical/bassDrop.mp3`,
|
||||
duration: 1.5,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['bass', 'drop', 'electronic'],
|
||||
};
|
||||
|
||||
export const vinylScratch: SfxEntry = {
|
||||
name: 'vinylScratch',
|
||||
category: 'musical',
|
||||
url: `${SFX_BASE_URL}/musical/vinylScratch.mp3`,
|
||||
duration: 0.8,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['vinyl', 'scratch', 'dj'],
|
||||
};
|
||||
|
||||
export const countdownBeep: SfxEntry = {
|
||||
name: 'countdownBeep',
|
||||
category: 'musical',
|
||||
url: `${SFX_BASE_URL}/musical/countdownBeep.mp3`,
|
||||
duration: 1.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['countdown', 'beep', 'timer'],
|
||||
};
|
||||
|
||||
export const ding: SfxEntry = {
|
||||
name: 'ding',
|
||||
category: 'musical',
|
||||
url: `${SFX_BASE_URL}/musical/ding.mp3`,
|
||||
duration: 1.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['ding', 'alert', 'clear'],
|
||||
};
|
||||
|
||||
export const gong: SfxEntry = {
|
||||
name: 'gong',
|
||||
category: 'musical',
|
||||
url: `${SFX_BASE_URL}/musical/gong.mp3`,
|
||||
duration: 4.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['gong', 'resonant', 'deep'],
|
||||
};
|
||||
@@ -0,0 +1,152 @@
|
||||
import { SFX_BASE_URL } from './constants.js';
|
||||
import type { SfxEntry } from './types.js';
|
||||
|
||||
export const swoosh: SfxEntry = {
|
||||
name: 'swoosh',
|
||||
category: 'transitions',
|
||||
url: `${SFX_BASE_URL}/transitions/swoosh.mp3`,
|
||||
duration: 0.8,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['fast', 'movement', 'slide'],
|
||||
};
|
||||
|
||||
export const whooshUp: SfxEntry = {
|
||||
name: 'whooshUp',
|
||||
category: 'transitions',
|
||||
url: `${SFX_BASE_URL}/transitions/whooshUp.mp3`,
|
||||
duration: 0.6,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['rising', 'upward', 'movement'],
|
||||
};
|
||||
|
||||
export const whooshDown: SfxEntry = {
|
||||
name: 'whooshDown',
|
||||
category: 'transitions',
|
||||
url: `${SFX_BASE_URL}/transitions/whooshDown.mp3`,
|
||||
duration: 0.6,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['falling', 'downward', 'movement'],
|
||||
};
|
||||
|
||||
export const slideIn: SfxEntry = {
|
||||
name: 'slideIn',
|
||||
category: 'transitions',
|
||||
url: `${SFX_BASE_URL}/transitions/slideIn.mp3`,
|
||||
duration: 0.7,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['enter', 'smooth', 'slide'],
|
||||
};
|
||||
|
||||
export const slideOut: SfxEntry = {
|
||||
name: 'slideOut',
|
||||
category: 'transitions',
|
||||
url: `${SFX_BASE_URL}/transitions/slideOut.mp3`,
|
||||
duration: 0.7,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['exit', 'smooth', 'slide'],
|
||||
};
|
||||
|
||||
export const fadeIn: SfxEntry = {
|
||||
name: 'fadeIn',
|
||||
category: 'transitions',
|
||||
url: `${SFX_BASE_URL}/transitions/fadeIn.mp3`,
|
||||
duration: 1.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['gentle', 'appear', 'soft'],
|
||||
};
|
||||
|
||||
export const fadeOut: SfxEntry = {
|
||||
name: 'fadeOut',
|
||||
category: 'transitions',
|
||||
url: `${SFX_BASE_URL}/transitions/fadeOut.mp3`,
|
||||
duration: 1.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['gentle', 'disappear', 'soft'],
|
||||
};
|
||||
|
||||
export const swipe: SfxEntry = {
|
||||
name: 'swipe',
|
||||
category: 'transitions',
|
||||
url: `${SFX_BASE_URL}/transitions/swipe.mp3`,
|
||||
duration: 0.5,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['quick', 'lateral', 'movement'],
|
||||
};
|
||||
|
||||
export const snap: SfxEntry = {
|
||||
name: 'snap',
|
||||
category: 'transitions',
|
||||
url: `${SFX_BASE_URL}/transitions/snap.mp3`,
|
||||
duration: 0.3,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['instant', 'crisp', 'sharp'],
|
||||
};
|
||||
|
||||
export const popTransition: SfxEntry = {
|
||||
name: 'popTransition',
|
||||
category: 'transitions',
|
||||
url: `${SFX_BASE_URL}/transitions/popTransition.mp3`,
|
||||
duration: 0.4,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['pop', 'bounce', 'playful'],
|
||||
};
|
||||
|
||||
export const glitch: SfxEntry = {
|
||||
name: 'glitch',
|
||||
category: 'transitions',
|
||||
url: `${SFX_BASE_URL}/transitions/glitch.mp3`,
|
||||
duration: 0.8,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['digital', 'distortion', 'error'],
|
||||
};
|
||||
|
||||
export const pageTurn: SfxEntry = {
|
||||
name: 'pageTurn',
|
||||
category: 'transitions',
|
||||
url: `${SFX_BASE_URL}/transitions/pageTurn.mp3`,
|
||||
duration: 0.9,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['paper', 'flip', 'organic'],
|
||||
};
|
||||
|
||||
export const zip: SfxEntry = {
|
||||
name: 'zip',
|
||||
category: 'transitions',
|
||||
url: `${SFX_BASE_URL}/transitions/zip.mp3`,
|
||||
duration: 0.5,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['fast', 'zip', 'quick'],
|
||||
};
|
||||
|
||||
export const tapeStop: SfxEntry = {
|
||||
name: 'tapeStop',
|
||||
category: 'transitions',
|
||||
url: `${SFX_BASE_URL}/transitions/tapeStop.mp3`,
|
||||
duration: 1.2,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['retro', 'slowdown', 'analog'],
|
||||
};
|
||||
|
||||
export const reverse: SfxEntry = {
|
||||
name: 'reverse',
|
||||
category: 'transitions',
|
||||
url: `${SFX_BASE_URL}/transitions/reverse.mp3`,
|
||||
duration: 1.0,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['rewind', 'backward', 'retro'],
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
export type SfxCategory = 'transitions' | 'ui' | 'cinematic' | 'ambient' | 'musical';
|
||||
|
||||
export type SfxEntry = {
|
||||
readonly name: string;
|
||||
readonly category: SfxCategory;
|
||||
readonly url: string;
|
||||
readonly duration: number; // seconds
|
||||
readonly format: 'mp3';
|
||||
readonly license: 'CC0-1.0';
|
||||
readonly tags: readonly string[];
|
||||
};
|
||||
@@ -0,0 +1,122 @@
|
||||
import { SFX_BASE_URL } from './constants.js';
|
||||
import type { SfxEntry } from './types.js';
|
||||
|
||||
export const click: SfxEntry = {
|
||||
name: 'click',
|
||||
category: 'ui',
|
||||
url: `${SFX_BASE_URL}/ui/click.mp3`,
|
||||
duration: 0.2,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['button', 'press', 'interface'],
|
||||
};
|
||||
|
||||
export const tap: SfxEntry = {
|
||||
name: 'tap',
|
||||
category: 'ui',
|
||||
url: `${SFX_BASE_URL}/ui/tap.mp3`,
|
||||
duration: 0.15,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['touch', 'mobile', 'light'],
|
||||
};
|
||||
|
||||
export const success: SfxEntry = {
|
||||
name: 'success',
|
||||
category: 'ui',
|
||||
url: `${SFX_BASE_URL}/ui/success.mp3`,
|
||||
duration: 0.8,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['complete', 'positive', 'achievement'],
|
||||
};
|
||||
|
||||
export const error: SfxEntry = {
|
||||
name: 'error',
|
||||
category: 'ui',
|
||||
url: `${SFX_BASE_URL}/ui/error.mp3`,
|
||||
duration: 0.5,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['fail', 'negative', 'warning'],
|
||||
};
|
||||
|
||||
export const notification: SfxEntry = {
|
||||
name: 'notification',
|
||||
category: 'ui',
|
||||
url: `${SFX_BASE_URL}/ui/notification.mp3`,
|
||||
duration: 0.6,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['alert', 'message', 'ping'],
|
||||
};
|
||||
|
||||
export const pop: SfxEntry = {
|
||||
name: 'pop',
|
||||
category: 'ui',
|
||||
url: `${SFX_BASE_URL}/ui/pop.mp3`,
|
||||
duration: 0.3,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['bubble', 'playful', 'light'],
|
||||
};
|
||||
|
||||
export const toggle: SfxEntry = {
|
||||
name: 'toggle',
|
||||
category: 'ui',
|
||||
url: `${SFX_BASE_URL}/ui/toggle.mp3`,
|
||||
duration: 0.2,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['switch', 'on-off', 'flip'],
|
||||
};
|
||||
|
||||
export const confirm: SfxEntry = {
|
||||
name: 'confirm',
|
||||
category: 'ui',
|
||||
url: `${SFX_BASE_URL}/ui/confirm.mp3`,
|
||||
duration: 0.5,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['approve', 'accept', 'done'],
|
||||
};
|
||||
|
||||
export const cancel: SfxEntry = {
|
||||
name: 'cancel',
|
||||
category: 'ui',
|
||||
url: `${SFX_BASE_URL}/ui/cancel.mp3`,
|
||||
duration: 0.4,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['dismiss', 'close', 'reject'],
|
||||
};
|
||||
|
||||
export const hover: SfxEntry = {
|
||||
name: 'hover',
|
||||
category: 'ui',
|
||||
url: `${SFX_BASE_URL}/ui/hover.mp3`,
|
||||
duration: 0.15,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['mouse', 'focus', 'subtle'],
|
||||
};
|
||||
|
||||
export const select: SfxEntry = {
|
||||
name: 'select',
|
||||
category: 'ui',
|
||||
url: `${SFX_BASE_URL}/ui/select.mp3`,
|
||||
duration: 0.25,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['choose', 'pick', 'highlight'],
|
||||
};
|
||||
|
||||
export const typing: SfxEntry = {
|
||||
name: 'typing',
|
||||
category: 'ui',
|
||||
url: `${SFX_BASE_URL}/ui/typing.mp3`,
|
||||
duration: 0.1,
|
||||
format: 'mp3',
|
||||
license: 'CC0-1.0',
|
||||
tags: ['keyboard', 'input', 'keystroke'],
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"strict": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src"
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist", "src/**/*.test.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user