@rel-packages/osu-beatmap-preview 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +4 -4
- package/dist/index.js.map +16 -11
- package/dist/math/difficulty.d.ts.map +1 -1
- package/dist/parser/async_parser.d.ts +15 -0
- package/dist/parser/async_parser.d.ts.map +1 -0
- package/dist/parser/osz_loader.d.ts +1 -0
- package/dist/parser/osz_loader.d.ts.map +1 -1
- package/dist/parser/parser.worker.d.ts +49 -0
- package/dist/parser/parser.worker.d.ts.map +1 -0
- package/dist/player/audio_controller.d.ts +1 -0
- package/dist/player/audio_controller.d.ts.map +1 -1
- package/dist/player/player.d.ts +8 -8
- package/dist/player/player.d.ts.map +1 -1
- package/dist/renderer/backend/canvas_backend.d.ts +2 -0
- package/dist/renderer/backend/canvas_backend.d.ts.map +1 -1
- package/dist/renderer/backend/render_backend.d.ts +2 -0
- package/dist/renderer/backend/render_backend.d.ts.map +1 -1
- package/dist/renderer/drawable/drawable.d.ts +48 -0
- package/dist/renderer/drawable/drawable.d.ts.map +1 -0
- package/dist/renderer/drawable/drawable_hit_circle.d.ts +15 -0
- package/dist/renderer/drawable/drawable_hit_circle.d.ts.map +1 -0
- package/dist/renderer/drawable/drawable_slider.d.ts +38 -0
- package/dist/renderer/drawable/drawable_slider.d.ts.map +1 -0
- package/dist/renderer/drawable/index.d.ts +5 -0
- package/dist/renderer/drawable/index.d.ts.map +1 -0
- package/dist/renderer/drawable/transforms.d.ts +32 -0
- package/dist/renderer/drawable/transforms.d.ts.map +1 -0
- package/dist/renderer/mania/mania_renderer.d.ts.map +1 -1
- package/dist/renderer/standard/standard_renderer.d.ts +11 -16
- package/dist/renderer/standard/standard_renderer.d.ts.map +1 -1
- package/dist/skin/skin_config.d.ts +11 -1
- package/dist/skin/skin_config.d.ts.map +1 -1
- package/dist/skin/skin_ini_parser.d.ts +21 -0
- package/dist/skin/skin_ini_parser.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/types/beatmap.ts", "../src/types/result.ts", "../src/types/mods.ts", "../src/parser/osz_loader.ts", "../src/parser/beatmap_parser.ts", "../src/renderer/base_renderer.ts", "../src/renderer/backend/canvas_backend.ts", "../src/math/difficulty.ts", "../src/mods/mod_hard_rock.ts", "../src/mods/mod_easy.ts", "../src/mods/mod_double_time.ts", "../src/mods/mod_half_time.ts", "../src/mods/mod_hidden.ts", "../src/mods/index.ts", "../src/math/vector2.ts", "../src/math/curves.ts", "../src/skin/skin_config.ts", "../src/renderer/standard/standard_renderer.ts", "../src/renderer/mania/mania_renderer.ts", "../src/player/audio_controller.ts", "../src/player/video_controller.ts", "../src/player/hitsound_controller.ts", "../src/player/player.ts"],
|
|
3
|
+
"sources": ["../src/types/beatmap.ts", "../src/types/result.ts", "../src/types/mods.ts", "../src/parser/osz_loader.ts", "../src/parser/beatmap_parser.ts", "../src/parser/async_parser.ts", "../src/renderer/base_renderer.ts", "../src/renderer/backend/canvas_backend.ts", "../src/math/difficulty.ts", "../src/mods/mod_hard_rock.ts", "../src/mods/mod_easy.ts", "../src/mods/mod_double_time.ts", "../src/mods/mod_half_time.ts", "../src/mods/mod_hidden.ts", "../src/mods/index.ts", "../src/math/vector2.ts", "../src/math/curves.ts", "../src/skin/skin_config.ts", "../src/renderer/drawable/transforms.ts", "../src/renderer/drawable/drawable.ts", "../src/renderer/drawable/drawable_hit_circle.ts", "../src/renderer/drawable/drawable_slider.ts", "../src/renderer/standard/standard_renderer.ts", "../src/renderer/mania/mania_renderer.ts", "../src/player/audio_controller.ts", "../src/player/video_controller.ts", "../src/player/hitsound_controller.ts", "../src/player/player.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"// game modes\nexport enum GameMode {\n Standard = 0,\n Taiko = 1,\n Catch = 2,\n Mania = 3\n}\n\nexport interface IBeatmap {\n format_version: number;\n mode: GameMode;\n\n title: string;\n title_unicode: string;\n artist: string;\n artist_unicode: string;\n creator: string;\n version: string;\n\n ar: number;\n cs: number;\n od: number;\n hp: number;\n sv: number;\n tick_rate: number;\n\n timing_points: ITimingPoint[];\n objects: IHitObject[];\n\n circle_count: number;\n slider_count: number;\n spinner_count: number;\n hold_count: number;\n}\n\nexport interface IBeatmapInfo {\n filename: string;\n title: string;\n artist: string;\n version: string;\n mode: GameMode;\n ar: number;\n cs: number;\n od: number;\n hp: number;\n}\n\nexport enum SampleSet {\n Auto = 0,\n Normal = 1,\n Soft = 2,\n Drum = 3\n}\n\nexport interface ITimingPoint {\n time: number;\n ms_per_beat: number;\n change: boolean;\n sample_set: SampleSet;\n sample_index: number;\n volume: number;\n kiai: boolean;\n velocity: number;\n beat_length: number;\n}\n\nexport const HitObjectType = {\n Circle: 1 << 0,\n Slider: 1 << 1,\n NewCombo: 1 << 2,\n Spinner: 1 << 3,\n ComboSkip: (1 << 4) | (1 << 5) | (1 << 6),\n Hold: 1 << 7\n} as const;\n\nexport const HitSoundType = {\n Normal: 1 << 0,\n Whistle: 1 << 1,\n Finish: 1 << 2,\n Clap: 1 << 3\n} as const;\n\nexport interface IHitSample {\n normal_set: SampleSet;\n addition_set: SampleSet;\n index: number;\n volume: number;\n filename?: string;\n}\n\nexport interface IHitObject {\n time: number;\n type: number;\n\n hit_sound: number;\n hit_sample?: IHitSample;\n edge_sounds?: number[];\n edge_sets?: [SampleSet, SampleSet][];\n\n end_time: number;\n end_pos: [number, number];\n combo_number: number;\n combo_count: number;\n data: ICircleData | ISliderData | ISpinnerData | IHoldData;\n}\n\nexport interface ICircleData {\n pos: [number, number];\n}\n\nexport type SliderPathType = \"L\" | \"B\" | \"P\" | \"C\";\n\nexport interface ISliderData {\n pos: [number, number];\n path_type: SliderPathType;\n control_points: [number, number][];\n distance: number;\n repetitions: number;\n duration?: number;\n computed_path?: [number, number][];\n}\n\nexport interface ISpinnerData {\n end_time: number;\n}\n\nexport interface IHoldData {\n pos: [number, number];\n end_time: number;\n}\n\nexport const is_circle = (obj: IHitObject): boolean => (obj.type & HitObjectType.Circle) !== 0;\nexport const is_slider = (obj: IHitObject): boolean => (obj.type & HitObjectType.Slider) !== 0;\nexport const is_spinner = (obj: IHitObject): boolean => (obj.type & HitObjectType.Spinner) !== 0;\nexport const is_hold = (obj: IHitObject): boolean => (obj.type & HitObjectType.Hold) !== 0;\nexport const is_new_combo = (obj: IHitObject): boolean => (obj.type & HitObjectType.NewCombo) !== 0;\n",
|
|
6
6
|
"export enum ErrorCode {\n NoOsuFiles = \"NO_OSU_FILES\",\n DifficultyNotFound = \"DIFFICULTY_NOT_FOUND\",\n InvalidBeatmap = \"INVALID_BEATMAP\",\n UnsupportedMode = \"UNSUPPORTED_MODE\",\n\n // audio errors\n AudioNotLoaded = \"AUDIO_NOT_LOADED\",\n AudioDecodeError = \"AUDIO_DECODE_ERROR\",\n\n // general\n NotLoaded = \"NOT_LOADED\",\n Unknown = \"UNKNOWN\"\n}\n\nexport type Result<T> = { success: true; data: T } | { success: false; code: ErrorCode; reason: string };\n\nexport const ok = <T>(data: T): Result<T> => ({ success: true, data });\n\nexport const err = <T>(code: ErrorCode, reason: string): Result<T> => ({\n success: false,\n code,\n reason\n});\n\nexport const unwrap = <T>(result: Result<T>): T => {\n if (result.success) return result.data;\n throw new Error(`[${result.code}] ${result.reason}`);\n};\n\nexport const is_ok = <T>(result: Result<T>): result is { success: true; data: T } => {\n return result.success;\n};\n\nexport const is_err = <T>(result: Result<T>): result is { success: false; code: ErrorCode; reason: string } => {\n return !result.success;\n};\n",
|
|
7
7
|
"export const Mods = {\n None: 0,\n NoFail: 1 << 0,\n Easy: 1 << 1,\n TouchDevice: 1 << 2,\n Hidden: 1 << 3,\n HardRock: 1 << 4,\n SuddenDeath: 1 << 5,\n DoubleTime: 1 << 6,\n Relax: 1 << 7,\n HalfTime: 1 << 8,\n Nightcore: 1 << 9,\n Flashlight: 1 << 10,\n Autoplay: 1 << 11,\n SpunOut: 1 << 12,\n Autopilot: 1 << 13,\n Perfect: 1 << 14,\n FadeIn: 1 << 23,\n Mirror: 1 << 30\n} as const;\n\nexport const SpeedChangingMods = Mods.DoubleTime | Mods.HalfTime | Mods.Nightcore;\nexport const DifficultyChangingMods = Mods.HardRock | Mods.Easy | SpeedChangingMods;\n\nexport const mods_from_string = (str: string): number => {\n let mask = 0;\n const lower = str.toLowerCase();\n const mod_map: Record<string, number> = {\n nf: Mods.NoFail,\n ez: Mods.Easy,\n td: Mods.TouchDevice,\n hd: Mods.Hidden,\n hr: Mods.HardRock,\n sd: Mods.SuddenDeath,\n dt: Mods.DoubleTime,\n rx: Mods.Relax,\n ht: Mods.HalfTime,\n nc: Mods.Nightcore,\n fl: Mods.Flashlight,\n at: Mods.Autoplay,\n so: Mods.SpunOut,\n ap: Mods.Autopilot,\n pf: Mods.Perfect,\n fi: Mods.FadeIn,\n mr: Mods.Mirror\n };\n\n for (let i = 0; i < lower.length - 1; i += 2) {\n const mod = lower.slice(i, i + 2);\n if (mod_map[mod]) {\n mask |= mod_map[mod];\n }\n }\n\n return mask;\n};\n\nexport const mods_to_string = (mods: number): string => {\n const names: string[] = [];\n\n if (mods & Mods.NoFail) names.push(\"NF\");\n if (mods & Mods.Easy) names.push(\"EZ\");\n if (mods & Mods.Hidden) names.push(\"HD\");\n if (mods & Mods.HardRock) names.push(\"HR\");\n if (mods & Mods.SuddenDeath) names.push(\"SD\");\n if (mods & Mods.DoubleTime) names.push(\"DT\");\n if (mods & Mods.HalfTime) names.push(\"HT\");\n if (mods & Mods.Nightcore) names.push(\"NC\");\n if (mods & Mods.Flashlight) names.push(\"FL\");\n if (mods & Mods.SpunOut) names.push(\"SO\");\n if (mods & Mods.FadeIn) names.push(\"FI\");\n if (mods & Mods.Mirror) names.push(\"MR\");\n\n const idx_dt = names.indexOf(\"DT\");\n const idx_nc = names.indexOf(\"NC\");\n\n if (idx_dt >= 0 && idx_nc >= 0) {\n names.splice(idx_dt, 1);\n }\n\n return names.join(\"\");\n};\n\nexport const get_speed_multiplier = (mods: number): number => {\n if (mods & (Mods.DoubleTime | Mods.Nightcore)) return 1.5;\n if (mods & Mods.HalfTime) return 0.75;\n return 1.0;\n};\n\nconst EXCLUSIVE_MOD_GROUPS = [Mods.HardRock | Mods.Easy, Mods.DoubleTime | Mods.HalfTime | Mods.Nightcore, Mods.Hidden | Mods.FadeIn];\n\nexport const toggle_mod = (current: number, mod: number): number => {\n // turn off\n if (current & mod) {\n return current & ~mod;\n }\n\n // turn on\n let result = current;\n\n for (const group of EXCLUSIVE_MOD_GROUPS) {\n if (mod & group) {\n result &= ~group;\n }\n }\n\n return result | mod;\n};\n\nexport const has_mod = (mods: number, mod: number): boolean => (mods & mod) !== 0;\n\nexport type GameModeType = \"standard\" | \"mania\" | \"taiko\" | \"catch\";\n\nexport interface IModInfo {\n name: string;\n acronym: string;\n value: number;\n}\n\nexport const get_available_mods = (mode: GameModeType): IModInfo[] => {\n const common: IModInfo[] = [\n { name: \"No Fail\", acronym: \"NF\", value: Mods.NoFail },\n { name: \"Easy\", acronym: \"EZ\", value: Mods.Easy },\n { name: \"Hidden\", acronym: \"HD\", value: Mods.Hidden },\n { name: \"Double Time\", acronym: \"DT\", value: Mods.DoubleTime },\n { name: \"Half Time\", acronym: \"HT\", value: Mods.HalfTime },\n { name: \"Nightcore\", acronym: \"NC\", value: Mods.Nightcore }\n ];\n\n switch (mode) {\n case \"standard\":\n return [\n ...common,\n { name: \"Hard Rock\", acronym: \"HR\", value: Mods.HardRock },\n { name: \"Flashlight\", acronym: \"FL\", value: Mods.Flashlight }\n ];\n\n case \"mania\":\n return [...common, { name: \"Fade In\", acronym: \"FI\", value: Mods.FadeIn }, { name: \"Mirror\", acronym: \"MR\", value: Mods.Mirror }];\n\n case \"taiko\":\n case \"catch\":\n return [...common, { name: \"Hard Rock\", acronym: \"HR\", value: Mods.HardRock }];\n\n default:\n return common;\n }\n};\n",
|
|
8
|
-
"import JSZip from \"jszip\";\nimport type { IBeatmap } from \"../types/beatmap\";\nimport type { IBeatmapResources } from \"../types/resources\";\nimport {
|
|
8
|
+
"import JSZip from \"jszip\";\nimport type { IBeatmap } from \"../types/beatmap\";\nimport type { IBeatmapResources } from \"../types/resources\";\nimport { AsyncBeatmapParser } from \"./async_parser\";\n\nexport interface IOszLoaderOptions {\n // select difficulty by index or version name\n difficulty?: number | string;\n}\n\nexport class OszLoader {\n private parser = new AsyncBeatmapParser();\n\n // load from .osz archive (ArrayBuffer)\n async load_osz(data: ArrayBuffer, options?: IOszLoaderOptions): Promise<IBeatmapResources> {\n const zip = await JSZip.loadAsync(data);\n const files = new Map<string, ArrayBuffer>();\n\n // extract all files into memory\n for (const [name, file] of Object.entries(zip.files)) {\n if (!file.dir) {\n files.set(name, await file.async(\"arraybuffer\"));\n }\n }\n\n return this.load_from_files(files, options);\n }\n\n // load from pre-extracted files (for direct file access without .osz)\n async load_from_files(files: Map<string, ArrayBuffer | string>, options?: IOszLoaderOptions): Promise<IBeatmapResources> {\n // find all .osu files\n const osu_files = [...files.keys()].filter((f) => f.toLowerCase().endsWith(\".osu\"));\n\n if (osu_files.length === 0) {\n throw new Error(\"No .osu files found in beatmap\");\n }\n\n // list all difficulties (async via worker)\n const available_difficulties = await Promise.all(\n osu_files.map(async (file) => {\n const content = this.to_string(files.get(file)!);\n return this.parser.parse_info(content, file);\n })\n );\n\n // select difficulty\n const selected_file = this.select_difficulty(osu_files, files, options?.difficulty);\n const osu_content = this.to_string(files.get(selected_file)!);\n\n // parse full beatmap (async via worker)\n const beatmap = await this.parser.parse(osu_content);\n\n // extract resource info (async via worker)\n const [audio_filename, background_filename, video_info] = await Promise.all([\n this.parser.extract_audio_filename(osu_content),\n this.parser.extract_background_filename(osu_content),\n this.parser.extract_video_info(osu_content)\n ]);\n\n // convert files map to ArrayBuffer only\n const array_buffer_files = new Map<string, ArrayBuffer>();\n for (const [name, content] of files) {\n if (content instanceof ArrayBuffer) {\n array_buffer_files.set(name, content);\n } else {\n array_buffer_files.set(name, new TextEncoder().encode(content).buffer as ArrayBuffer);\n }\n }\n\n // extract audio\n let audio: ArrayBuffer | undefined;\n if (audio_filename) {\n audio = this.find_file(array_buffer_files, audio_filename);\n }\n\n // extract background\n let background: Blob | undefined;\n if (background_filename) {\n const bg_data = this.find_file(array_buffer_files, background_filename);\n if (bg_data) {\n background = new Blob([bg_data]);\n }\n }\n\n // extract video\n let video: Blob | undefined;\n let video_offset: number | undefined;\n if (video_info) {\n const video_data = this.find_file(array_buffer_files, video_info.filename);\n if (video_data) {\n video = new Blob([video_data]);\n video_offset = video_info.offset;\n }\n }\n\n return {\n beatmap,\n available_difficulties,\n files: array_buffer_files,\n audio,\n background,\n video,\n audio_filename: audio_filename ?? undefined,\n background_filename: background_filename ?? undefined,\n video_filename: video_info?.filename,\n video_offset\n };\n }\n\n // list available difficulties in a beatmap set\n async list_difficulties(data: ArrayBuffer): Promise<string[]> {\n const zip = await JSZip.loadAsync(data);\n const osu_files: string[] = [];\n\n for (const name of Object.keys(zip.files)) {\n if (name.toLowerCase().endsWith(\".osu\")) {\n osu_files.push(name);\n }\n }\n\n const difficulties: string[] = [];\n\n for (const file of osu_files) {\n const content = await zip.files[file].async(\"string\");\n const version_match = content.match(/Version:\\s*(.+)/);\n difficulties.push(version_match ? version_match[1].trim() : file);\n }\n\n return difficulties;\n }\n\n private select_difficulty(osu_files: string[], files: Map<string, ArrayBuffer | string>, selector?: number | string): string {\n // no selector: use first file\n if (selector === undefined) {\n return osu_files[0];\n }\n\n // number: select by index\n if (typeof selector === \"number\") {\n if (selector < 0 || selector >= osu_files.length) {\n throw new Error(`Difficulty index ${selector} out of range (0-${osu_files.length - 1})`);\n }\n return osu_files[selector];\n }\n\n // string: search by version name\n for (const file of osu_files) {\n const content = this.to_string(files.get(file)!);\n const version_match = content.match(/Version:\\s*(.+)/);\n if (version_match && version_match[1].trim() === selector) {\n return file;\n }\n }\n\n // fallback: partial match\n for (const file of osu_files) {\n if (file.toLowerCase().includes(selector.toLowerCase())) {\n return file;\n }\n }\n\n throw new Error(`Difficulty \"${selector}\" not found`);\n }\n\n private find_file(files: Map<string, ArrayBuffer>, filename: string): ArrayBuffer | undefined {\n // exact match\n if (files.has(filename)) {\n return files.get(filename);\n }\n\n // case-insensitive search\n const lower = filename.toLowerCase();\n for (const [name, data] of files) {\n if (name.toLowerCase() === lower) {\n return data;\n }\n }\n\n return undefined;\n }\n\n private to_string(data: ArrayBuffer | string): string {\n if (typeof data === \"string\") return data;\n return new TextDecoder().decode(data);\n }\n}\n",
|
|
9
9
|
"import type { IBeatmap, IHitObject, ICircleData, ISliderData, ISpinnerData, IHoldData, SliderPathType, IBeatmapInfo } from \"../types/beatmap\";\nimport { GameMode, HitObjectType } from \"../types/beatmap\";\n\nexport class BeatmapParser {\n private beatmap!: IBeatmap;\n private section: string = \"\";\n\n parse(content: string): IBeatmap {\n this.beatmap = this.create_empty_beatmap();\n this.section = \"\";\n\n const lines = content.split(\"\\n\");\n\n for (const line of lines) {\n this.parse_line(line);\n }\n\n // fallback: old maps have no AR, use OD\n if (this.beatmap.ar === -1) {\n this.beatmap.ar = this.beatmap.od;\n }\n\n return this.beatmap;\n }\n\n parse_info(content: string, filename: string): IBeatmapInfo {\n this.beatmap = this.create_empty_beatmap();\n this.section = \"\";\n\n const lines = content.split(\"\\n\");\n\n for (const line of lines) {\n this.parse_line(line);\n // stop after difficulty section to save time\n if (this.section === \"Events\" || this.section === \"TimingPoints\" || this.section === \"Colours\" || this.section === \"HitObjects\") {\n break;\n }\n }\n\n if (this.beatmap.ar === -1) {\n this.beatmap.ar = this.beatmap.od;\n }\n\n return {\n filename,\n title: this.beatmap.title,\n artist: this.beatmap.artist,\n version: this.beatmap.version,\n mode: this.beatmap.mode,\n ar: this.beatmap.ar,\n cs: this.beatmap.cs,\n od: this.beatmap.od,\n hp: this.beatmap.hp\n };\n }\n\n private create_empty_beatmap(): IBeatmap {\n return {\n format_version: 1,\n mode: GameMode.Standard,\n title: \"\",\n title_unicode: \"\",\n artist: \"\",\n artist_unicode: \"\",\n creator: \"\",\n version: \"\",\n ar: -1,\n cs: 5,\n od: 5,\n hp: 5,\n sv: 1,\n tick_rate: 1,\n timing_points: [],\n objects: [],\n circle_count: 0,\n slider_count: 0,\n spinner_count: 0,\n hold_count: 0\n };\n }\n\n private parse_line(raw_line: string): void {\n if (raw_line.startsWith(\" \") || raw_line.startsWith(\"_\")) return;\n\n const line = raw_line.trim();\n if (line.length === 0 || line.startsWith(\"//\")) return;\n\n if (line.startsWith(\"[\") && line.endsWith(\"]\")) {\n this.section = line.slice(1, -1);\n return;\n }\n\n const format_match = line.match(/osu file format v(\\d+)/);\n if (format_match) {\n this.beatmap.format_version = parseInt(format_match[1]);\n return;\n }\n\n switch (this.section) {\n case \"General\":\n this.parse_general(line);\n break;\n case \"Metadata\":\n this.parse_metadata(line);\n break;\n case \"Difficulty\":\n this.parse_difficulty(line);\n break;\n case \"TimingPoints\":\n this.parse_timing_point(line);\n break;\n case \"HitObjects\":\n this.parse_hit_object(line);\n break;\n }\n }\n\n private parse_general(line: string): void {\n const [key, value] = this.split_property(line);\n if (key === \"Mode\") this.beatmap.mode = parseInt(value) as GameMode;\n }\n\n private parse_metadata(line: string): void {\n const [key, value] = this.split_property(line);\n switch (key) {\n case \"Title\":\n this.beatmap.title = value;\n break;\n case \"TitleUnicode\":\n this.beatmap.title_unicode = value;\n break;\n case \"Artist\":\n this.beatmap.artist = value;\n break;\n case \"ArtistUnicode\":\n this.beatmap.artist_unicode = value;\n break;\n case \"Creator\":\n this.beatmap.creator = value;\n break;\n case \"Version\":\n this.beatmap.version = value;\n break;\n }\n }\n\n private parse_difficulty(line: string): void {\n const [key, value] = this.split_property(line);\n const num = parseFloat(value);\n switch (key) {\n case \"CircleSize\":\n this.beatmap.cs = num;\n break;\n case \"OverallDifficulty\":\n this.beatmap.od = num;\n break;\n case \"ApproachRate\":\n this.beatmap.ar = num;\n break;\n case \"HPDrainRate\":\n this.beatmap.hp = num;\n break;\n case \"SliderMultiplier\":\n this.beatmap.sv = num;\n break;\n case \"SliderTickRate\":\n this.beatmap.tick_rate = num;\n break;\n }\n }\n\n private current_beat_length: number = 500;\n\n private parse_timing_point(line: string): void {\n const parts = line.split(\",\");\n if (parts.length < 2) return;\n\n const time = parseFloat(parts[0]);\n const ms_per_beat = parseFloat(parts[1]);\n const sample_set = parseInt(parts[3] ?? \"0\");\n const sample_index = parseInt(parts[4] ?? \"0\");\n const volume = parseInt(parts[5] ?? \"100\");\n const change = parts.length >= 7 ? parts[6].trim() !== \"0\" : true;\n const kiai = parts.length >= 8 ? (parseInt(parts[7]) & 1) !== 0 : false;\n\n // inherited points have negative ms_per_beat\n const is_inherited = ms_per_beat < 0;\n const velocity = is_inherited ? -100 / ms_per_beat : 1.0;\n\n // beat_length comes from uninherited (red) points only\n if (!is_inherited && ms_per_beat > 0) {\n this.current_beat_length = ms_per_beat;\n }\n\n this.beatmap.timing_points.push({\n time,\n ms_per_beat,\n change,\n sample_set,\n sample_index,\n volume,\n kiai,\n velocity,\n beat_length: this.current_beat_length\n });\n }\n\n private parse_hit_object(line: string): void {\n const parts = line.split(\",\");\n if (parts.length < 4) return;\n\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n const time = parseFloat(parts[2]);\n const type = parseInt(parts[3]);\n const hit_sound = parseInt(parts[4] ?? \"0\");\n\n const obj: IHitObject = {\n time,\n type,\n hit_sound,\n end_time: time,\n end_pos: [x, y],\n combo_number: 0,\n combo_count: 0,\n data: { pos: [x, y] } as ICircleData\n };\n\n if (type & HitObjectType.Circle) {\n this.beatmap.circle_count++;\n obj.data = { pos: [x, y] } as ICircleData;\n this.parse_extras(parts, 5, obj);\n } else if (type & HitObjectType.Slider) {\n if (parts.length < 8) return;\n this.beatmap.slider_count++;\n const slider_data = this.parse_slider_data(parts, x, y);\n obj.data = slider_data;\n\n // sliders have variable length fields (edgeSounds, edgeSets) before hitSample\n // usually: curve, slides, length, edgeSounds, edgeSets, hitSample\n // hitSample is strictly the last part if present\n\n // edgeSounds\n if (parts.length > 8) {\n obj.edge_sounds = parts[8].split(\"|\").map((s) => parseInt(s));\n }\n\n // edgeSets\n if (parts.length > 9) {\n obj.edge_sets = parts[9].split(\"|\").map((s) => {\n const sets = s.split(\":\");\n return [parseInt(sets[0]), parseInt(sets[1])];\n });\n }\n\n this.parse_extras(parts, 10, obj);\n } else if (type & HitObjectType.Spinner) {\n this.beatmap.spinner_count++;\n const end_time = parseInt(parts[5]);\n obj.data = { end_time } as ISpinnerData;\n obj.end_time = end_time;\n obj.end_pos = [256, 192];\n this.parse_extras(parts, 6, obj);\n } else if (type & HitObjectType.Hold) {\n this.beatmap.hold_count++;\n const end_time = parseInt(parts[5].split(\":\")[0]);\n obj.data = { pos: [x, y], end_time } as IHoldData;\n obj.end_time = end_time;\n this.parse_extras(parts, 6, obj);\n }\n\n this.beatmap.objects.push(obj);\n }\n\n private parse_extras(parts: string[], index: number, obj: IHitObject): void {\n if (index < parts.length) {\n const sample_str = parts[index];\n if (sample_str && sample_str.includes(\":\")) {\n const sample_parts = sample_str.split(\":\");\n obj.hit_sample = {\n normal_set: parseInt(sample_parts[0]),\n addition_set: parseInt(sample_parts[1]),\n index: parseInt(sample_parts[2]),\n volume: parseInt(sample_parts[3]),\n filename: sample_parts[4] || undefined\n };\n }\n }\n }\n\n private parse_slider_data(parts: string[], x: number, y: number): ISliderData {\n const curve_data = parts[5].split(\"|\");\n const path_type = curve_data[0] as SliderPathType;\n\n const control_points: [number, number][] = [];\n for (let i = 1; i < curve_data.length; i++) {\n const point = curve_data[i].split(\":\");\n control_points.push([parseInt(point[0]), parseInt(point[1])]);\n }\n\n const repetitions = parseInt(parts[6]);\n const distance = parseFloat(parts[7]);\n\n return {\n pos: [x, y],\n path_type,\n control_points,\n repetitions,\n distance\n };\n }\n\n private split_property(line: string): [string, string] {\n const idx = line.indexOf(\":\");\n if (idx === -1) return [line, \"\"];\n return [line.slice(0, idx).trim(), line.slice(idx + 1).trim()];\n }\n}\n\nconst HEADER_LIMIT = 4096;\n\nexport const extract_preview_time = (content: string): number => {\n const match = content.slice(0, HEADER_LIMIT).match(/PreviewTime:\\s*([+-]?\\d+)/);\n return match ? parseInt(match[1]) : -1;\n};\n\nexport const extract_audio_filename = (content: string): string | null => {\n const match = content.slice(0, HEADER_LIMIT).match(/AudioFilename:\\s*(.+)/);\n return match ? match[1].trim() : null;\n};\n\nexport const extract_background_filename = (content: string): string | null => {\n const match = content.slice(0, HEADER_LIMIT).match(/0,0,\"([^\"]+)\"/);\n return match ? match[1] : null;\n};\n\nexport const extract_video_info = (content: string): { filename: string; offset: number } | null => {\n const match = content.slice(0, HEADER_LIMIT).match(/(?:Video|1),(-?\\d+),\"([^\"]+)\"/);\n if (!match) return null;\n return { offset: parseInt(match[1]), filename: match[2] };\n};\n",
|
|
10
|
+
"import type { IBeatmap, IBeatmapInfo } from \"../types/beatmap\";\nimport { BeatmapParser, extract_audio_filename, extract_background_filename, extract_video_info, extract_preview_time } from \"./beatmap_parser\";\n\nconst parser = new BeatmapParser();\n\nconst defer = <T>(fn: () => T): Promise<T> => {\n return new Promise((resolve, reject) => {\n queueMicrotask(() => {\n try {\n resolve(fn());\n } catch (e) {\n reject(e);\n }\n });\n });\n};\n\nexport class AsyncBeatmapParser {\n parse(content: string): Promise<IBeatmap> {\n return defer(() => parser.parse(content));\n }\n\n parse_info(content: string, filename: string): Promise<IBeatmapInfo> {\n return defer(() => parser.parse_info(content, filename));\n }\n\n extract_audio_filename(content: string): Promise<string | null> {\n return defer(() => extract_audio_filename(content));\n }\n\n extract_background_filename(content: string): Promise<string | null> {\n return defer(() => extract_background_filename(content));\n }\n\n extract_video_info(content: string): Promise<{ filename: string; offset: number } | null> {\n return defer(() => extract_video_info(content));\n }\n\n extract_preview_time(content: string): Promise<number> {\n return defer(() => extract_preview_time(content));\n }\n\n dispose(): void {\n // no-op for sync implementation\n }\n}\n\nlet shared_parser: AsyncBeatmapParser | null = null;\n\nexport const get_shared_parser = (): AsyncBeatmapParser => {\n if (!shared_parser) {\n shared_parser = new AsyncBeatmapParser();\n }\n return shared_parser;\n};\n",
|
|
10
11
|
"import type { IRenderBackend, RenderImage } from \"./backend/render_backend\";\nimport type { IBeatmap, IHitObject } from \"../types/beatmap\";\nimport type { ISkinConfig } from \"../skin/skin_config\";\n\n// osu! playfield is 512x384 in osu! pixels\nexport const PLAYFIELD_WIDTH = 512;\nexport const PLAYFIELD_HEIGHT = 384;\n\n// grid levels (osu! editor)\nexport enum GridLevel {\n None = 0,\n Large = 32,\n Medium = 16,\n Small = 8,\n Tiny = 4\n}\n\nexport interface IRendererConfig {\n // playfield offset from canvas origin\n offset_x: number;\n offset_y: number;\n\n // scale factor for playfield\n scale: number;\n\n // show playfield border\n show_playfield: boolean;\n playfield_color: string;\n playfield_opacity: number;\n\n // grid overlay\n grid_level: GridLevel;\n grid_color: string;\n grid_opacity: number;\n\n // high DPI rendering (device pixel ratio)\n use_high_dpi: boolean;\n}\n\nexport const DEFAULT_RENDERER_CONFIG: IRendererConfig = {\n offset_x: 64,\n offset_y: 48,\n scale: 1,\n\n show_playfield: true,\n playfield_color: \"#ffffff\",\n playfield_opacity: 0.1,\n\n grid_level: GridLevel.None,\n grid_color: \"#ffffff\",\n grid_opacity: 0.35,\n\n use_high_dpi: true\n};\n\nexport abstract class BaseRenderer {\n protected backend: IRenderBackend;\n protected skin: ISkinConfig;\n protected config: IRendererConfig;\n protected mods: number;\n\n protected beatmap!: IBeatmap;\n protected objects: IHitObject[] = [];\n protected background_image: RenderImage | null = null;\n\n constructor(backend: IRenderBackend, skin: ISkinConfig, mods: number = 0, config: IRendererConfig = DEFAULT_RENDERER_CONFIG) {\n this.backend = backend;\n this.skin = skin;\n this.mods = mods;\n this.config = { ...DEFAULT_RENDERER_CONFIG, ...config };\n }\n\n set_background(image: RenderImage | null): void {\n this.background_image = image;\n }\n\n update_config(config: Partial<IRendererConfig>): void {\n this.config = { ...this.config, ...config };\n }\n\n abstract initialize(beatmap: IBeatmap): void;\n abstract render(time: number): void;\n\n // update mods and recalculate difficulty attributes\n abstract set_mods(mods: number): void;\n\n dispose(): void {\n this.objects = [];\n }\n\n // render playfield border\n protected render_playfield(custom_w?: number, custom_h?: number, custom_x?: number, custom_y?: number): void {\n if (!this.config.show_playfield) return;\n\n const { backend, config } = this;\n const w = custom_w ?? PLAYFIELD_WIDTH;\n const h = custom_h ?? PLAYFIELD_HEIGHT;\n const x = custom_x ?? 0;\n const y = custom_y ?? 0;\n\n backend.save();\n backend.set_alpha(config.playfield_opacity);\n\n // draw border box\n backend.begin_path();\n backend.move_to(x, y);\n backend.line_to(x + w, y);\n backend.line_to(x + w, y + h);\n backend.line_to(x, y + h);\n backend.line_to(x, y);\n backend.stroke_path(config.playfield_color, 2);\n\n backend.restore();\n }\n\n // render grid overlay\n protected render_grid(): void {\n if (this.config.grid_level === GridLevel.None) return;\n\n const { backend, config } = this;\n const spacing = config.grid_level as number;\n\n backend.save();\n backend.set_alpha(config.grid_opacity);\n\n // vertical lines\n for (let x = 0; x <= PLAYFIELD_WIDTH; x += spacing) {\n backend.begin_path();\n backend.move_to(x, 0);\n backend.line_to(x, PLAYFIELD_HEIGHT);\n backend.stroke_path(config.grid_color, x % (spacing * 4) === 0 ? 1 : 0.5);\n }\n\n // horizontal lines\n for (let y = 0; y <= PLAYFIELD_HEIGHT; y += spacing) {\n backend.begin_path();\n backend.move_to(0, y);\n backend.line_to(PLAYFIELD_WIDTH, y);\n backend.stroke_path(config.grid_color, y % (spacing * 4) === 0 ? 1 : 0.5);\n }\n\n backend.restore();\n }\n\n protected render_background(): void {\n if (!this.background_image) return;\n\n const { backend } = this;\n backend.save();\n backend.set_alpha(0.3); // dim background\n\n const canvas_w = backend.width;\n const canvas_h = backend.height;\n const { width: img_w, height: img_h } = this.background_image;\n\n if (img_w > 0 && img_h > 0) {\n // maintain aspect ratio but fill the entire area\n const scale = Math.max(canvas_w / img_w, canvas_h / img_h);\n const draw_w = img_w * scale;\n const draw_h = img_h * scale;\n const x = (canvas_w - draw_w) / 2;\n const y = (canvas_h - draw_h) / 2;\n\n backend.draw_image(this.background_image, x, y, draw_w, draw_h);\n } else {\n backend.draw_image(this.background_image, 0, 0, canvas_w, canvas_h);\n }\n\n backend.restore();\n }\n\n protected get_visible_objects(time: number, preempt: number, fade_out: number): IHitObject[] {\n const visible: IHitObject[] = [];\n\n for (const obj of this.objects) {\n const appear_time = obj.time - preempt;\n const disappear_time = obj.end_time + fade_out;\n\n if (time >= appear_time && time <= disappear_time) {\n visible.push(obj);\n }\n }\n\n return visible;\n }\n}\n",
|
|
11
|
-
"import type { IRenderBackend, GradientStop, RenderImage, LineCap, LineJoin, TextAlign, TextBaseline, CompositeOperation } from \"./render_backend\";\n\nexport class CanvasBackend implements IRenderBackend {\n private ctx!: CanvasRenderingContext2D;\n private _width: number = 0;\n private _height: number = 0;\n private _dpr: number = 1;\n\n get width(): number {\n return this._width;\n }\n get height(): number {\n return this._height;\n }\n\n initialize(container: HTMLCanvasElement, use_high_dpi: boolean = true): void {\n this._dpr = use_high_dpi ? window.devicePixelRatio || 1 : 1;\n\n const display_width = container.clientWidth || container.width;\n const display_height = container.clientHeight || container.height;\n\n container.width = display_width * this._dpr;\n container.height = display_height * this._dpr;\n\n const ctx = container.getContext(\"2d\", {\n alpha: true,\n desynchronized: true\n });\n\n if (!ctx) {\n throw new Error(\"Failed to get 2D context\");\n }\n\n this.ctx = ctx;\n this._width = display_width;\n this._height = display_height;\n\n ctx.scale(this._dpr, this._dpr);\n ctx.imageSmoothingEnabled = true;\n ctx.imageSmoothingQuality = \"high\";\n }\n\n clear(): void {\n this.ctx.save();\n this.ctx.setTransform(this._dpr, 0, 0, this._dpr, 0, 0);\n this.ctx.clearRect(0, 0, this._width, this._height);\n this.ctx.restore();\n }\n\n dispose(): void {\n // no-op for canvas\n }\n\n resize(width: number, height: number): void {\n this._width = width;\n this._height = height;\n this._dpr = window.devicePixelRatio || 1;\n\n const canvas = this.ctx.canvas;\n canvas.width = width * this._dpr;\n canvas.height = height * this._dpr;\n canvas.style.width = `${width}px`;\n canvas.style.height = `${height}px`;\n\n this.ctx.resetTransform();\n this.ctx.scale(this._dpr, this._dpr);\n this.ctx.imageSmoothingEnabled = true;\n this.ctx.imageSmoothingQuality = \"high\";\n }\n\n draw_circle(x: number, y: number, radius: number, fill_color: string, stroke_color?: string, stroke_width?: number): void {\n const ctx = this.ctx;\n ctx.beginPath();\n ctx.arc(x, y, radius, 0, Math.PI * 2);\n\n if (fill_color && fill_color !== \"transparent\") {\n ctx.fillStyle = fill_color;\n ctx.fill();\n }\n\n if (stroke_color && stroke_width && stroke_width > 0) {\n ctx.strokeStyle = stroke_color;\n ctx.lineWidth = stroke_width;\n ctx.stroke();\n }\n }\n\n draw_arc(\n x: number,\n y: number,\n radius: number,\n start_angle: number,\n end_angle: number,\n stroke_color: string,\n stroke_width: number,\n ccw: boolean = false\n ): void {\n const ctx = this.ctx;\n ctx.beginPath();\n ctx.arc(x, y, radius, start_angle, end_angle, ccw);\n ctx.strokeStyle = stroke_color;\n ctx.lineWidth = stroke_width;\n ctx.stroke();\n }\n\n draw_rect(x: number, y: number, width: number, height: number, fill_color: string): void {\n this.ctx.fillStyle = fill_color;\n this.ctx.fillRect(x, y, width, height);\n }\n\n draw_rect_gradient(x: number, y: number, width: number, height: number, gradient: any): void {\n this.ctx.fillStyle = gradient;\n this.ctx.fillRect(x, y, width, height);\n }\n\n create_linear_gradient(x0: number, y0: number, x1: number, y1: number, stops: GradientStop[]): any {\n const gradient = this.ctx.createLinearGradient(x0, y0, x1, y1);\n for (const stop of stops) {\n gradient.addColorStop(stop.offset, stop.color);\n }\n return gradient;\n }\n\n draw_text(\n text: string,\n x: number,\n y: number,\n font: string,\n fill_color: string,\n align: TextAlign = \"left\",\n baseline: TextBaseline = \"alphabetic\"\n ): void {\n const ctx = this.ctx;\n ctx.font = font;\n ctx.fillStyle = fill_color;\n ctx.textAlign = align as CanvasTextAlign;\n ctx.textBaseline = baseline as CanvasTextBaseline;\n ctx.fillText(text, x, y);\n }\n\n begin_path(): void {\n this.ctx.beginPath();\n }\n\n move_to(x: number, y: number): void {\n this.ctx.moveTo(x, y);\n }\n\n line_to(x: number, y: number): void {\n this.ctx.lineTo(x, y);\n }\n\n bezier_curve_to(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): void {\n this.ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);\n }\n\n quadratic_curve_to(cpx: number, cpy: number, x: number, y: number): void {\n this.ctx.quadraticCurveTo(cpx, cpy, x, y);\n }\n\n arc_to(x: number, y: number, radius: number, start: number, end: number, ccw?: boolean): void {\n this.ctx.arc(x, y, radius, start, end, ccw);\n }\n\n rect(x: number, y: number, width: number, height: number): void {\n this.ctx.rect(x, y, width, height);\n }\n\n clip(): void {\n this.ctx.clip();\n }\n\n stroke_path(color: string, width: number, cap: LineCap = \"butt\", join: LineJoin = \"miter\"): void {\n const ctx = this.ctx;\n ctx.strokeStyle = color;\n ctx.lineWidth = width;\n ctx.lineCap = cap;\n ctx.lineJoin = join;\n ctx.stroke();\n }\n\n fill_path(color: string): void {\n this.ctx.fillStyle = color;\n this.ctx.fill();\n }\n\n save(): void {\n this.ctx.save();\n }\n\n restore(): void {\n this.ctx.restore();\n }\n\n translate(x: number, y: number): void {\n this.ctx.translate(x, y);\n }\n\n scale(x: number, y: number): void {\n this.ctx.scale(x, y);\n }\n\n rotate(angle: number): void {\n this.ctx.rotate(angle);\n }\n\n set_alpha(alpha: number): void {\n this.ctx.globalAlpha = alpha;\n }\n\n set_shadow(color: string, blur: number): void {\n this.ctx.shadowColor = color;\n this.ctx.shadowBlur = blur;\n }\n\n set_composite_operation(op: CompositeOperation): void {\n this.ctx.globalCompositeOperation = op;\n }\n\n draw_image(image: RenderImage, x: number, y: number, width?: number, height?: number): void {\n if (width !== undefined && height !== undefined) {\n this.ctx.drawImage(image.source, x, y, width, height);\n } else {\n this.ctx.drawImage(image.source, x, y);\n }\n }\n\n draw_image_part(image: RenderImage, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void;\n draw_image_part(image: RenderImage, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void {\n this.ctx.drawImage(image.source, sx, sy, sw, sh, dx, dy, dw, dh);\n }\n\n render_slider_to_image(\n path: [number, number][],\n radius: number,\n border_color: string,\n body_color: string,\n scale: number,\n body_opacity: number = 1.0,\n border_opacity: number = 1.0\n ): RenderImage | null {\n let min_x = Infinity,\n min_y = Infinity,\n max_x = -Infinity,\n max_y = -Infinity;\n for (const p of path) {\n if (p[0] < min_x) min_x = p[0];\n if (p[0] > max_x) max_x = p[0];\n if (p[1] < min_y) min_y = p[1];\n if (p[1] > max_y) max_y = p[1];\n }\n\n const padding = radius + 2;\n min_x -= padding;\n min_y -= padding;\n max_x += padding;\n max_y += padding;\n\n const width = Math.ceil((max_x - min_x) * scale);\n const height = Math.ceil((max_y - min_y) * scale);\n\n if (width <= 0 || height <= 0) return null;\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return null;\n\n ctx.save();\n ctx.scale(scale, scale);\n ctx.translate(-min_x, -min_y);\n\n const draw_path = () => {\n ctx.beginPath();\n if (path.length > 0) {\n ctx.moveTo(path[0][0], path[0][1]);\n for (let i = 1; i < path.length; i++) {\n ctx.lineTo(path[i][0], path[i][1]);\n }\n }\n };\n\n ctx.lineCap = \"round\";\n ctx.lineJoin = \"round\";\n\n // draw full border\n ctx.globalAlpha = border_opacity;\n ctx.strokeStyle = border_color;\n ctx.lineWidth = radius * 2;\n draw_path();\n ctx.stroke();\n\n // if body is semi-transparent, we MUST mask out the center of the border\n // to prevent it from bleeding through the body\n const body_radius = radius * 0.872;\n if (body_opacity < 1.0) {\n ctx.globalCompositeOperation = \"destination-out\";\n ctx.globalAlpha = 1.0;\n ctx.lineWidth = body_radius * 2;\n draw_path();\n ctx.stroke();\n ctx.globalCompositeOperation = \"source-over\";\n }\n\n // draw body\n ctx.globalAlpha = body_opacity;\n ctx.strokeStyle = body_color;\n ctx.lineWidth = body_radius * 2;\n\n draw_path();\n\n ctx.stroke();\n ctx.restore();\n\n return {\n source: canvas,\n width,\n height,\n min_x,\n min_y\n };\n }\n}\n",
|
|
12
|
-
"export interface IDifficultyRange {\n min: number;\n mid: number;\n max: number;\n}\n\nexport const PREEMPT_RANGE: IDifficultyRange = { min: 1800, mid: 1200, max: 450 };\nexport const PREEMPT_MIN = 450;\n\nexport const difficulty_range = (difficulty: number, range: IDifficultyRange): number => {\n if (difficulty > 5) {\n return range.mid + ((range.max - range.mid) * (difficulty - 5)) / 5;\n }\n if (difficulty < 5) {\n return range.mid + ((range.mid - range.min) * (difficulty - 5)) / 5;\n }\n return range.mid;\n};\n\nexport const inverse_difficulty_range = (value: number, range: IDifficultyRange): number => {\n const toward_max = Math.sign(value - range.mid) === Math.sign(range.max - range.mid);\n if (toward_max) return ((value - range.mid) / (range.max - range.mid)) * 5 + 5;\n return ((value - range.mid) / (range.mid - range.min)) * 5 + 5;\n};\n\nexport const calculate_preempt = (ar: number): number => difficulty_range(ar, PREEMPT_RANGE);\nexport const calculate_fade_in = (preempt: number): number => 400 * Math.min(1, preempt / PREEMPT_MIN);\n\
|
|
12
|
+
"import type { IRenderBackend, GradientStop, RenderImage, LineCap, LineJoin, TextAlign, TextBaseline, CompositeOperation } from \"./render_backend\";\n\nexport class CanvasBackend implements IRenderBackend {\n private ctx!: CanvasRenderingContext2D;\n private _width: number = 0;\n private _height: number = 0;\n private _dpr: number = 1;\n\n get width(): number {\n return this._width;\n }\n get height(): number {\n return this._height;\n }\n\n initialize(container: HTMLCanvasElement, use_high_dpi: boolean = true): void {\n this._dpr = use_high_dpi ? window.devicePixelRatio || 1 : 1;\n\n const display_width = container.clientWidth || container.width;\n const display_height = container.clientHeight || container.height;\n\n container.width = display_width * this._dpr;\n container.height = display_height * this._dpr;\n\n const ctx = container.getContext(\"2d\", {\n alpha: true,\n desynchronized: true\n });\n\n if (!ctx) {\n throw new Error(\"Failed to get 2D context\");\n }\n\n this.ctx = ctx;\n this._width = display_width;\n this._height = display_height;\n\n ctx.scale(this._dpr, this._dpr);\n ctx.imageSmoothingEnabled = true;\n ctx.imageSmoothingQuality = \"high\";\n }\n\n clear(): void {\n this.ctx.save();\n this.ctx.setTransform(this._dpr, 0, 0, this._dpr, 0, 0);\n this.ctx.clearRect(0, 0, this._width, this._height);\n this.ctx.restore();\n }\n\n dispose(): void {\n // no-op for canvas\n }\n\n resize(width: number, height: number): void {\n this._width = width;\n this._height = height;\n this._dpr = window.devicePixelRatio || 1;\n\n const canvas = this.ctx.canvas;\n canvas.width = width * this._dpr;\n canvas.height = height * this._dpr;\n canvas.style.width = `${width}px`;\n canvas.style.height = `${height}px`;\n\n this.ctx.resetTransform();\n this.ctx.scale(this._dpr, this._dpr);\n this.ctx.imageSmoothingEnabled = true;\n this.ctx.imageSmoothingQuality = \"high\";\n }\n\n draw_circle(x: number, y: number, radius: number, fill_color: string, stroke_color?: string, stroke_width?: number): void {\n const ctx = this.ctx;\n ctx.beginPath();\n ctx.arc(x, y, radius, 0, Math.PI * 2);\n\n if (fill_color && fill_color !== \"transparent\") {\n ctx.fillStyle = fill_color;\n ctx.fill();\n }\n\n if (stroke_color && stroke_width && stroke_width > 0) {\n ctx.strokeStyle = stroke_color;\n ctx.lineWidth = stroke_width;\n ctx.stroke();\n }\n }\n\n draw_arc(\n x: number,\n y: number,\n radius: number,\n start_angle: number,\n end_angle: number,\n stroke_color: string,\n stroke_width: number,\n ccw: boolean = false\n ): void {\n const ctx = this.ctx;\n ctx.beginPath();\n ctx.arc(x, y, radius, start_angle, end_angle, ccw);\n ctx.strokeStyle = stroke_color;\n ctx.lineWidth = stroke_width;\n ctx.stroke();\n }\n\n draw_rect(x: number, y: number, width: number, height: number, fill_color: string): void {\n this.ctx.fillStyle = fill_color;\n this.ctx.fillRect(x, y, width, height);\n }\n\n draw_rect_gradient(x: number, y: number, width: number, height: number, gradient: any): void {\n this.ctx.fillStyle = gradient;\n this.ctx.fillRect(x, y, width, height);\n }\n\n create_linear_gradient(x0: number, y0: number, x1: number, y1: number, stops: GradientStop[]): any {\n const gradient = this.ctx.createLinearGradient(x0, y0, x1, y1);\n for (const stop of stops) {\n gradient.addColorStop(stop.offset, stop.color);\n }\n return gradient;\n }\n\n draw_text(\n text: string,\n x: number,\n y: number,\n font: string,\n fill_color: string,\n align: TextAlign = \"left\",\n baseline: TextBaseline = \"alphabetic\"\n ): void {\n const ctx = this.ctx;\n ctx.font = font;\n ctx.fillStyle = fill_color;\n ctx.textAlign = align as CanvasTextAlign;\n ctx.textBaseline = baseline as CanvasTextBaseline;\n ctx.fillText(text, x, y);\n }\n\n begin_path(): void {\n this.ctx.beginPath();\n }\n\n move_to(x: number, y: number): void {\n this.ctx.moveTo(x, y);\n }\n\n line_to(x: number, y: number): void {\n this.ctx.lineTo(x, y);\n }\n\n bezier_curve_to(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): void {\n this.ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);\n }\n\n quadratic_curve_to(cpx: number, cpy: number, x: number, y: number): void {\n this.ctx.quadraticCurveTo(cpx, cpy, x, y);\n }\n\n arc_to(x: number, y: number, radius: number, start: number, end: number, ccw?: boolean): void {\n this.ctx.arc(x, y, radius, start, end, ccw);\n }\n\n rect(x: number, y: number, width: number, height: number): void {\n this.ctx.rect(x, y, width, height);\n }\n\n clip(): void {\n this.ctx.clip();\n }\n\n stroke_path(color: string, width: number, cap: LineCap = \"butt\", join: LineJoin = \"miter\"): void {\n const ctx = this.ctx;\n ctx.strokeStyle = color;\n ctx.lineWidth = width;\n ctx.lineCap = cap;\n ctx.lineJoin = join;\n ctx.stroke();\n }\n\n fill_path(color: string): void {\n this.ctx.fillStyle = color;\n this.ctx.fill();\n }\n\n close_path(): void {\n this.ctx.closePath();\n }\n\n save(): void {\n this.ctx.save();\n }\n\n restore(): void {\n this.ctx.restore();\n }\n\n translate(x: number, y: number): void {\n this.ctx.translate(x, y);\n }\n\n scale(x: number, y: number): void {\n this.ctx.scale(x, y);\n }\n\n rotate(angle: number): void {\n this.ctx.rotate(angle);\n }\n\n set_alpha(alpha: number): void {\n this.ctx.globalAlpha = alpha;\n }\n\n set_shadow(color: string, blur: number): void {\n this.ctx.shadowColor = color;\n this.ctx.shadowBlur = blur;\n }\n\n set_composite_operation(op: CompositeOperation): void {\n this.ctx.globalCompositeOperation = op;\n }\n\n set_blend_mode(mode: \"normal\" | \"lighter\" | \"multiply\" | \"screen\"): void {\n const ops: Record<string, GlobalCompositeOperation> = {\n normal: \"source-over\",\n lighter: \"lighter\",\n multiply: \"multiply\",\n screen: \"screen\"\n };\n this.ctx.globalCompositeOperation = ops[mode] ?? \"source-over\";\n }\n\n draw_image(image: RenderImage, x: number, y: number, width?: number, height?: number): void {\n if (width !== undefined && height !== undefined) {\n this.ctx.drawImage(image.source, x, y, width, height);\n } else {\n this.ctx.drawImage(image.source, x, y);\n }\n }\n\n draw_image_part(image: RenderImage, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void;\n draw_image_part(image: RenderImage, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void {\n this.ctx.drawImage(image.source, sx, sy, sw, sh, dx, dy, dw, dh);\n }\n\n render_slider_to_image(\n path: [number, number][],\n radius: number,\n border_color: string,\n body_color: string,\n scale: number,\n body_opacity: number = 1.0,\n border_opacity: number = 1.0\n ): RenderImage | null {\n let min_x = Infinity,\n min_y = Infinity,\n max_x = -Infinity,\n max_y = -Infinity;\n for (const p of path) {\n if (p[0] < min_x) min_x = p[0];\n if (p[0] > max_x) max_x = p[0];\n if (p[1] < min_y) min_y = p[1];\n if (p[1] > max_y) max_y = p[1];\n }\n\n const padding = radius + 2;\n min_x -= padding;\n min_y -= padding;\n max_x += padding;\n max_y += padding;\n\n const width = Math.ceil((max_x - min_x) * scale);\n const height = Math.ceil((max_y - min_y) * scale);\n\n if (width <= 0 || height <= 0) return null;\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return null;\n\n ctx.save();\n ctx.scale(scale, scale);\n ctx.translate(-min_x, -min_y);\n\n const draw_path = () => {\n ctx.beginPath();\n if (path.length > 0) {\n ctx.moveTo(path[0][0], path[0][1]);\n for (let i = 1; i < path.length; i++) {\n ctx.lineTo(path[i][0], path[i][1]);\n }\n }\n };\n\n ctx.lineCap = \"round\";\n ctx.lineJoin = \"round\";\n\n // draw full border\n ctx.globalAlpha = border_opacity;\n ctx.strokeStyle = border_color;\n ctx.lineWidth = radius * 2;\n draw_path();\n ctx.stroke();\n\n // if body is semi-transparent, we MUST mask out the center of the border\n // to prevent it from bleeding through the body\n const body_radius = radius * 0.872;\n if (body_opacity < 1.0) {\n ctx.globalCompositeOperation = \"destination-out\";\n ctx.globalAlpha = 1.0;\n ctx.lineWidth = body_radius * 2;\n draw_path();\n ctx.stroke();\n ctx.globalCompositeOperation = \"source-over\";\n }\n\n // draw body\n ctx.globalAlpha = body_opacity;\n ctx.strokeStyle = body_color;\n ctx.lineWidth = body_radius * 2;\n\n draw_path();\n\n ctx.stroke();\n ctx.restore();\n\n return {\n source: canvas,\n width,\n height,\n min_x,\n min_y\n };\n }\n}\n",
|
|
13
|
+
"export interface IDifficultyRange {\n min: number;\n mid: number;\n max: number;\n}\n\nexport const PREEMPT_RANGE: IDifficultyRange = { min: 1800, mid: 1200, max: 450 };\nexport const PREEMPT_MIN = 450;\n\nexport const difficulty_range = (difficulty: number, range: IDifficultyRange): number => {\n if (difficulty > 5) {\n return range.mid + ((range.max - range.mid) * (difficulty - 5)) / 5;\n }\n if (difficulty < 5) {\n return range.mid + ((range.mid - range.min) * (difficulty - 5)) / 5;\n }\n return range.mid;\n};\n\nexport const inverse_difficulty_range = (value: number, range: IDifficultyRange): number => {\n const toward_max = Math.sign(value - range.mid) === Math.sign(range.max - range.mid);\n if (toward_max) return ((value - range.mid) / (range.max - range.mid)) * 5 + 5;\n return ((value - range.mid) / (range.mid - range.min)) * 5 + 5;\n};\n\nexport const calculate_preempt = (ar: number): number => difficulty_range(ar, PREEMPT_RANGE);\nexport const calculate_fade_in = (preempt: number): number => 400 * Math.min(1, preempt / PREEMPT_MIN);\n\nexport const calculate_scale = (cs: number): number => {\n const normalized = (cs - 5) / 5; // maps [0, 10] to [-1, 1]\n return (1 - 0.7 * normalized) / 2;\n};\n\nexport const calculate_radius = (cs: number): number => calculate_scale(cs) * 64;\n",
|
|
13
14
|
"import type { IMod, IApplicableToDifficulty, IBeatmapDifficulty } from \"./types\";\n\nconst ADJUST_RATIO = 1.4;\nconst CS_RATIO = 1.3;\n\nexport const ModHardRock: IMod & IApplicableToDifficulty = {\n name: \"Hard Rock\",\n acronym: \"HR\",\n\n apply_to_difficulty(d: IBeatmapDifficulty): void {\n d.cs = Math.min(d.cs * CS_RATIO, 10);\n d.ar = Math.min(d.ar * ADJUST_RATIO, 10);\n d.od = Math.min(d.od * ADJUST_RATIO, 10);\n d.hp = Math.min(d.hp * ADJUST_RATIO, 10);\n }\n};\n",
|
|
14
15
|
"import type { IMod, IApplicableToDifficulty, IBeatmapDifficulty } from \"./types\";\n\nconst ADJUST_RATIO = 0.5;\n\nexport const ModEasy: IMod & IApplicableToDifficulty = {\n name: \"Easy\",\n acronym: \"EZ\",\n\n apply_to_difficulty(d: IBeatmapDifficulty): void {\n d.cs *= ADJUST_RATIO;\n d.ar *= ADJUST_RATIO;\n d.od *= ADJUST_RATIO;\n d.hp *= ADJUST_RATIO;\n }\n};\n",
|
|
15
16
|
"import type { IMod, IApplicableToRate } from \"./types\";\n\nconst RATE_MULTIPLIER = 1.5;\n\nexport const ModDoubleTime: IMod & IApplicableToRate = {\n name: \"Double Time\",\n acronym: \"DT\",\n\n get_rate_multiplier: () => RATE_MULTIPLIER\n};\n\nexport const ModNightcore: IMod & IApplicableToRate = {\n name: \"Nightcore\",\n acronym: \"NC\",\n\n get_rate_multiplier: () => RATE_MULTIPLIER\n};\n",
|
|
@@ -18,15 +19,19 @@
|
|
|
18
19
|
"import type { IBeatmapDifficulty } from \"./types\";\nimport { Mods } from \"../types/mods\";\nimport { ModHardRock } from \"./mod_hard_rock\";\nimport { ModEasy } from \"./mod_easy\";\nimport { calculate_preempt, inverse_difficulty_range, PREEMPT_RANGE } from \"../math/difficulty\";\n\nexport type { IMod, IApplicableToDifficulty, IApplicableToRate, IBeatmapDifficulty } from \"./types\";\nexport { ModHardRock } from \"./mod_hard_rock\";\nexport { ModEasy } from \"./mod_easy\";\nexport { ModDoubleTime, ModNightcore } from \"./mod_double_time\";\nexport { ModHalfTime } from \"./mod_half_time\";\nexport { ModHidden, HD_FADE_IN_MULTIPLIER, HD_FADE_OUT_MULTIPLIER } from \"./mod_hidden\";\n\nexport const get_rate_multiplier = (mods: number): number => {\n if (mods & (Mods.DoubleTime | Mods.Nightcore)) {\n return 1.5;\n }\n if (mods & Mods.HalfTime) {\n return 0.75;\n }\n return 1.0;\n};\n\nexport const apply_mods_to_difficulty = (difficulty: IBeatmapDifficulty, mods: number): void => {\n if (mods & Mods.Easy) ModEasy.apply_to_difficulty(difficulty);\n if (mods & Mods.HardRock) ModHardRock.apply_to_difficulty(difficulty);\n};\n\nexport const apply_rate_to_ar = (ar: number, rate: number): number => {\n if (rate === 1.0) return ar;\n\n // convert AR to preempt ms, scale by rate, convert back to AR\n const preempt_ms = calculate_preempt(ar) / rate;\n return inverse_difficulty_range(preempt_ms, PREEMPT_RANGE);\n};\n\nexport const get_adjusted_difficulty = (cs: number, ar: number, od: number, hp: number, mods: number): IBeatmapDifficulty => {\n const difficulty: IBeatmapDifficulty = { cs, ar, od, hp };\n\n apply_mods_to_difficulty(difficulty, mods);\n\n const rate = get_rate_multiplier(mods);\n difficulty.ar = apply_rate_to_ar(difficulty.ar, rate);\n\n return difficulty;\n};\n",
|
|
19
20
|
"export type Vec2 = [number, number];\n\nexport const vec2_add = (a: Vec2, b: Vec2): Vec2 => [a[0] + b[0], a[1] + b[1]];\nexport const vec2_sub = (a: Vec2, b: Vec2): Vec2 => [a[0] - b[0], a[1] - b[1]];\nexport const vec2_mul = (a: Vec2, s: number): Vec2 => [a[0] * s, a[1] * s];\nexport const vec2_div = (a: Vec2, s: number): Vec2 => [a[0] / s, a[1] / s];\nexport const vec2_dot = (a: Vec2, b: Vec2): number => a[0] * b[0] + a[1] * b[1];\nexport const vec2_len = (v: Vec2): number => Math.sqrt(v[0] * v[0] + v[1] * v[1]);\nexport const vec2_len_sq = (v: Vec2): number => v[0] * v[0] + v[1] * v[1];\nexport const vec2_dist = (a: Vec2, b: Vec2): number => vec2_len(vec2_sub(a, b));\nexport const vec2_normalize = (v: Vec2): Vec2 => {\n const len = vec2_len(v);\n return len > 0 ? vec2_div(v, len) : [0, 0];\n};\n\nexport const lerp = (a: number, b: number, t: number): number => a + (b - a) * t;\nexport const vec2_lerp = (a: Vec2, b: Vec2, t: number): Vec2 => [lerp(a[0], b[0], t), lerp(a[1], b[1], t)];\nexport const clamp = (x: number, min: number, max: number): number => Math.min(max, Math.max(min, x));\n",
|
|
20
21
|
"import { type Vec2, vec2_add, vec2_sub, vec2_mul, vec2_len, vec2_lerp } from \"./vector2\";\n\nexport const flatten_bezier = (points: Vec2[], tolerance: number = 0.25): Vec2[] => {\n if (points.length < 2) return [...points];\n\n const result: Vec2[] = [];\n flatten_bezier_recursive(points, result, tolerance);\n return result;\n};\n\nconst flatten_bezier_recursive = (points: Vec2[], output: Vec2[], tolerance: number): void => {\n if (is_flat_enough(points, tolerance)) {\n if (output.length === 0) {\n output.push(points[0]);\n }\n output.push(points[points.length - 1]);\n return;\n }\n\n const left: Vec2[] = [];\n const right: Vec2[] = [];\n subdivide_bezier(points, left, right);\n\n flatten_bezier_recursive(left, output, tolerance);\n flatten_bezier_recursive(right, output, tolerance);\n};\n\nconst is_flat_enough = (points: Vec2[], tolerance: number): boolean => {\n if (points.length <= 2) return true;\n\n // check if all middle points are close enough to the line from first to last\n const start = points[0];\n const end = points[points.length - 1];\n\n for (let i = 1; i < points.length - 1; i++) {\n if (point_to_line_dist(points[i], start, end) > tolerance) {\n return false;\n }\n }\n return true;\n};\n\nconst point_to_line_dist = (point: Vec2, line_start: Vec2, line_end: Vec2): number => {\n const line = vec2_sub(line_end, line_start);\n const len_sq = line[0] * line[0] + line[1] * line[1];\n\n if (len_sq === 0) return vec2_len(vec2_sub(point, line_start));\n\n const t = Math.max(0, Math.min(1, ((point[0] - line_start[0]) * line[0] + (point[1] - line_start[1]) * line[1]) / len_sq));\n\n const proj: Vec2 = [line_start[0] + t * line[0], line_start[1] + t * line[1]];\n\n return vec2_len(vec2_sub(point, proj));\n};\n\nconst subdivide_bezier = (points: Vec2[], left: Vec2[], right: Vec2[]): void => {\n const n = points.length;\n const midpoints: Vec2[][] = [points];\n\n for (let i = 1; i < n; i++) {\n midpoints[i] = [];\n for (let j = 0; j < n - i; j++) {\n midpoints[i][j] = vec2_lerp(midpoints[i - 1][j], midpoints[i - 1][j + 1], 0.5);\n }\n }\n\n for (let i = 0; i < n; i++) {\n left.push(midpoints[i][0]);\n right.push(midpoints[n - 1 - i][i]);\n }\n};\n\nexport const flatten_linear = (start: Vec2, end: Vec2, distance: number): Vec2[] => {\n const dir = vec2_sub(end, start);\n const len = vec2_len(dir);\n\n if (len === 0) return [start];\n\n const normalized: Vec2 = [dir[0] / len, dir[1] / len];\n const actual_end: Vec2 = vec2_add(start, vec2_mul(normalized, distance));\n\n return [start, actual_end];\n};\n\nexport const flatten_perfect = (points: Vec2[], distance: number): Vec2[] => {\n if (points.length !== 3) {\n // fallback to bezier if not exactly 3 points\n return flatten_bezier(points);\n }\n\n const [a, b, c] = points;\n\n // find circle center using 3 points\n const center = find_circle_center(a, b, c);\n if (!center) {\n // points are collinear, treat as linear\n return flatten_linear(a, c, distance);\n }\n\n const radius = vec2_len(vec2_sub(a, center));\n const start_angle = Math.atan2(a[1] - center[1], a[0] - center[0]);\n const end_angle = Math.atan2(c[1] - center[1], c[0] - center[0]);\n\n // determine direction (clockwise or counter-clockwise)\n const cross = (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);\n const ccw = cross > 0;\n\n // calculate arc length and clamp to distance\n let arc_angle = end_angle - start_angle;\n if (ccw && arc_angle < 0) arc_angle += 2 * Math.PI;\n if (!ccw && arc_angle > 0) arc_angle -= 2 * Math.PI;\n\n const arc_length = Math.abs(arc_angle) * radius;\n\n // generate points along arc\n const num_points = Math.max(2, Math.ceil((Math.abs(arc_angle) * radius) / 4));\n const result: Vec2[] = [];\n\n for (let i = 0; i <= num_points; i++) {\n const t = i / num_points;\n const angle = start_angle + arc_angle * t * Math.min(1, distance / arc_length);\n result.push([center[0] + radius * Math.cos(angle), center[1] + radius * Math.sin(angle)]);\n }\n\n return result;\n};\n\nconst find_circle_center = (a: Vec2, b: Vec2, c: Vec2): Vec2 | null => {\n const d = 2 * (a[0] * (b[1] - c[1]) + b[0] * (c[1] - a[1]) + c[0] * (a[1] - b[1]));\n\n if (Math.abs(d) < 0.001) return null; // collinear\n\n const ux =\n ((a[0] * a[0] + a[1] * a[1]) * (b[1] - c[1]) + (b[0] * b[0] + b[1] * b[1]) * (c[1] - a[1]) + (c[0] * c[0] + c[1] * c[1]) * (a[1] - b[1])) / d;\n const uy =\n ((a[0] * a[0] + a[1] * a[1]) * (c[0] - b[0]) + (b[0] * b[0] + b[1] * b[1]) * (a[0] - c[0]) + (c[0] * c[0] + c[1] * c[1]) * (b[0] - a[0])) / d;\n\n return [ux, uy];\n};\n\nexport const flatten_catmull = (points: Vec2[]): Vec2[] => {\n if (points.length < 2) return [...points];\n\n const result: Vec2[] = [];\n\n for (let i = 0; i < points.length - 1; i++) {\n const p0 = points[Math.max(0, i - 1)];\n const p1 = points[i];\n const p2 = points[i + 1];\n const p3 = points[Math.min(points.length - 1, i + 2)];\n\n const segments = 50;\n for (let j = 0; j <= segments; j++) {\n const t = j / segments;\n result.push(catmull_point(p0, p1, p2, p3, t));\n }\n }\n\n return result;\n};\n\nconst catmull_point = (p0: Vec2, p1: Vec2, p2: Vec2, p3: Vec2, t: number): Vec2 => {\n const t2 = t * t;\n const t3 = t2 * t;\n\n return [\n 0.5 * (2 * p1[0] + (-p0[0] + p2[0]) * t + (2 * p0[0] - 5 * p1[0] + 4 * p2[0] - p3[0]) * t2 + (-p0[0] + 3 * p1[0] - 3 * p2[0] + p3[0]) * t3),\n 0.5 * (2 * p1[1] + (-p0[1] + p2[1]) * t + (2 * p0[1] - 5 * p1[1] + 4 * p2[1] - p3[1]) * t2 + (-p0[1] + 3 * p1[1] - 3 * p2[1] + p3[1]) * t3)\n ];\n};\n",
|
|
21
|
-
"export interface ISkinConfig {\n combo_colors: string[];\n\n // circle rendering\n circle_border_width: number;\n hit_circle_opacity: number;\n approach_circle_width: number;\n\n // slider rendering\n slider_body_opacity: number;\n slider_border_opacity: number;\n slider_tick_opacity: number;\n slider_tick_size: number;\n\n // follow circle (slider ball outer ring)\n follow_circle_factor: number;\n follow_circle_width: number;\n follow_circle_opacity: number;\n follow_circle_color: string;\n follow_circle_use_combo_color: boolean;\n\n // slider ball (inner circle)\n slider_ball_color: string;\n slider_ball_opacity: number;\n enable_slider_ball: boolean;\n\n // follow points (dots between objects)\n follow_point_width: number;\n\n // spinner\n spinner_size: number;\n spinner_center_size: number;\n\n // mania\n mania_lane_width: number;\n mania_note_height: number;\n mania_hit_position: number;\n mania_lane_spacing: number;\n mania_lane_colors: Record<number, string[]>;\n\n // general\n font_family: string;\n hit_animation_duration: number;\n hit_animation_scale: number;\n\n // animation toggles\n enable_hit_animations: boolean;\n enable_follow_circle_animations: boolean;\n
|
|
22
|
-
"import type { IBeatmap, IHitObject, ISliderData, ITimingPoint } from \"../../types/beatmap\";\nimport { is_circle, is_slider, is_spinner, is_new_combo } from \"../../types/beatmap\";\nimport { Mods, has_mod } from \"../../types/mods\";\nimport { calculate_preempt, calculate_fade_in, calculate_radius } from \"../../math/difficulty\";\nimport { get_adjusted_difficulty } from \"../../mods\";\nimport { flatten_bezier, flatten_linear, flatten_perfect, flatten_catmull } from \"../../math/curves\";\nimport { vec2_sub, vec2_len, vec2_lerp, vec2_normalize, lerp, clamp, type Vec2 } from \"../../math/vector2\";\nimport { BaseRenderer, type IRendererConfig, DEFAULT_RENDERER_CONFIG } from \"../base_renderer\";\nimport type { IRenderBackend, RenderImage } from \"../backend/render_backend\";\nimport type { ISkinConfig } from \"../../skin/skin_config\";\nimport { get_combo_color } from \"../../skin/skin_config\";\n\nconst ease_out_cubic = (t: number): number => 1 - Math.pow(1 - t, 3);\nconst flip_y = (y: number): number => 384 - y;\n\nexport class StandardRenderer extends BaseRenderer {\n private radius: number = 32;\n private preempt: number = 1200;\n private fade_in: number = 600;\n private timing_points: ITimingPoint[] = [];\n\n // cache for rendered sliders\n private slider_cache: Map<\n IHitObject,\n {\n image: RenderImage;\n scale: number;\n }\n > = new Map();\n\n constructor(backend: IRenderBackend, skin: ISkinConfig, mods: number = 0, config: IRendererConfig = DEFAULT_RENDERER_CONFIG) {\n super(backend, skin, mods, config);\n }\n\n initialize(beatmap: IBeatmap): void {\n this.beatmap = beatmap;\n // deep copy objects to prevent permanent modification (prevents double-flipping with HR)\n // ensure objects are sorted by time for consistent rendering order (z-index)\n this.objects = JSON.parse(JSON.stringify(beatmap.objects)).sort((a: IHitObject, b: IHitObject) => a.time - b.time);\n this.timing_points = this.process_timing_points([...beatmap.timing_points]);\n\n // clear caches when map changes\n this.slider_cache.clear();\n\n const difficulty = get_adjusted_difficulty(beatmap.cs, beatmap.ar, 0, 0, this.mods);\n\n this.radius = calculate_radius(difficulty.cs);\n this.preempt = calculate_preempt(difficulty.ar);\n this.fade_in = calculate_fade_in(this.preempt);\n\n this.preprocess_objects();\n }\n\n set_mods(mods: number): void {\n this.mods = mods;\n\n if (this.beatmap) {\n this.initialize(this.beatmap);\n }\n }\n\n private process_timing_points(points: ITimingPoint[]): ITimingPoint[] {\n if (points.length === 0) return points;\n\n points[0].time = 0;\n let base_ms_per_beat = points[0].ms_per_beat;\n\n for (const point of points) {\n if (point.ms_per_beat < 0) {\n point.ms_per_beat = base_ms_per_beat * (-point.ms_per_beat / 100);\n } else {\n base_ms_per_beat = point.ms_per_beat;\n }\n }\n\n return points.reverse();\n }\n\n private preprocess_objects(): void {\n let combo_number = 0;\n let combo_count = 1;\n\n for (const obj of this.objects) {\n if (is_new_combo(obj)) {\n combo_number = (combo_number + 1) % this.skin.combo_colors.length;\n combo_count = 1;\n } else {\n combo_count++;\n }\n obj.combo_number = combo_number;\n obj.combo_count = combo_count;\n\n if (is_slider(obj)) {\n const data = obj.data as ISliderData;\n\n if (has_mod(this.mods, Mods.HardRock)) {\n data.pos = [data.pos[0], flip_y(data.pos[1])];\n data.control_points = data.control_points.map((p) => [p[0], flip_y(p[1])] as [number, number]);\n }\n\n data.computed_path = this.compute_slider_path(data);\n\n const timing = this.get_timing_at(obj.time);\n const duration = (data.distance / (100 * this.beatmap.sv)) * timing.ms_per_beat;\n\n data.duration = duration;\n obj.end_time = obj.time + duration * data.repetitions;\n obj.end_pos = this.get_slider_position(data, obj.end_time - obj.time, duration);\n } else if (is_spinner(obj)) {\n obj.end_pos = [256, 192];\n } else {\n const data = obj.data as { pos: Vec2 };\n\n if (has_mod(this.mods, Mods.HardRock)) {\n data.pos = [data.pos[0], flip_y(data.pos[1])];\n }\n\n obj.end_pos = data.pos;\n }\n }\n }\n\n private compute_slider_path(slider: ISliderData): Vec2[] {\n if (slider.path_type === \"L\") {\n return flatten_linear(slider.pos, slider.control_points[0], slider.distance);\n }\n\n const all_points: Vec2[] = [slider.pos, ...slider.control_points];\n\n switch (slider.path_type) {\n case \"P\":\n return flatten_perfect(all_points, slider.distance);\n case \"C\":\n return flatten_catmull(all_points);\n default:\n return this.flatten_multibezier(all_points, slider.distance);\n }\n }\n\n private flatten_multibezier(points: Vec2[], max_distance: number): Vec2[] {\n const segments: Vec2[][] = [];\n let current: Vec2[] = [points[0]];\n\n for (let i = 1; i < points.length; i++) {\n const [prev, cur] = [points[i - 1], points[i]];\n\n if (prev[0] === cur[0] && prev[1] === cur[1]) {\n if (current.length > 1) segments.push(current);\n current = [cur];\n } else {\n current.push(cur);\n }\n }\n\n if (current.length > 1) segments.push(current);\n\n const all_points: Vec2[] = [];\n for (const segment of segments) {\n const flattened = flatten_bezier(segment);\n all_points.push(...flattened);\n }\n\n return this.clamp_path_to_distance(all_points, max_distance);\n }\n\n private clamp_path_to_distance(path: Vec2[], max_distance: number): Vec2[] {\n if (path.length < 2) return path;\n\n const result: Vec2[] = [path[0]];\n let distance = 0;\n\n for (let i = 1; i < path.length; i++) {\n const segment_length = vec2_len(vec2_sub(path[i], path[i - 1]));\n\n if (distance + segment_length >= max_distance) {\n const remaining = max_distance - distance;\n const t = remaining / segment_length;\n result.push(vec2_lerp(path[i - 1], path[i], t));\n break;\n }\n\n distance += segment_length;\n result.push(path[i]);\n }\n\n return result;\n }\n\n private get_timing_at(time: number): ITimingPoint {\n for (const point of this.timing_points) {\n if (point.time <= time) {\n return point;\n }\n }\n return this.timing_points[this.timing_points.length - 1];\n }\n\n render(time: number): void {\n const { backend, config } = this;\n\n this.render_background();\n\n backend.save();\n backend.translate(config.offset_x, config.offset_y);\n backend.scale(config.scale, config.scale);\n\n this.render_playfield();\n this.render_grid();\n\n // get visible objects sorted by start time (ascending)\n const visible = this.get_visible_objects(time, this.preempt, 200);\n\n // follow points between adjacent objects\n for (let i = 0; i < visible.length - 1; i++) {\n const obj = visible[i];\n const next = visible[i + 1];\n if (!is_spinner(obj) && !is_spinner(next)) {\n this.draw_follow_point(obj, next, time);\n }\n }\n\n // draw in two passes to ensure overlays (approach circles, slider balls) are always on top\n // reverse time order: later objects at back, earlier objects on top\n visible.reverse();\n\n for (const obj of visible) {\n if (is_slider(obj)) {\n this.draw_slider(obj, time);\n } else if (is_circle(obj)) {\n this.draw_hit_circle(obj, time);\n } else if (is_spinner(obj)) {\n this.draw_spinner(obj, time);\n }\n }\n\n for (const obj of visible) {\n const has_approach_circle = !has_mod(this.mods, Mods.Hidden) && time <= obj.time && this.skin.enable_approach_circle;\n\n if (has_approach_circle && (is_slider(obj) || is_circle(obj))) {\n this.draw_approach_circle(obj, time);\n }\n\n if (is_slider(obj) && time > obj.time && time <= obj.end_time + 240) {\n this.draw_follow_circle(obj, time);\n }\n }\n\n backend.restore();\n }\n\n private get_slider_body_opacity(obj: IHitObject, time: number): number {\n const appear_time = obj.time - this.preempt;\n\n if (has_mod(this.mods, Mods.Hidden)) {\n // HD: \"long fade\" - fades out gradually from fade_in completion until slider ends\n const hd_fade_in = this.preempt * 0.4;\n const fade_in_complete_time = appear_time + hd_fade_in;\n\n if (time < appear_time) return 0;\n\n // fade in\n if (time < fade_in_complete_time) {\n return clamp((time - appear_time) / hd_fade_in, 0, 1);\n }\n\n // gradual fade out from fade_in completion until slider ends\n const fade_out_duration = obj.end_time - fade_in_complete_time;\n const progress = clamp((time - fade_in_complete_time) / fade_out_duration, 0, 1);\n return 1 - progress;\n }\n\n // normal mode\n if (time < appear_time) return 0;\n let opacity = clamp((time - appear_time) / this.fade_in, 0, 1);\n\n // fade out after slider ends\n if (time > obj.end_time) {\n const fade_t = clamp((time - obj.end_time) / 200, 0, 1);\n opacity = 1 - ease_out_cubic(fade_t);\n }\n\n return clamp(opacity, 0, 1);\n }\n\n private draw_approach_circle(obj: IHitObject, time: number): void {\n if (has_mod(this.mods, Mods.Hidden)) return;\n const { backend, skin, radius, preempt, fade_in } = this;\n const pos = (obj.data as { pos: Vec2 }).pos;\n const appear_time = obj.time - preempt;\n\n if (time < appear_time || time > obj.time) return;\n\n const progress = (obj.time - time) / preempt;\n // approach circle: 4x scale at appear_time → 1x at hit time (lazer behavior)\n const scale = 1 + progress * 3;\n const size = radius * scale;\n\n const opacity_duration = Math.min(fade_in * 2, preempt);\n const opacity = clamp((time - appear_time) / opacity_duration, 0, 0.9);\n\n backend.set_alpha(opacity);\n backend.draw_circle(pos[0], pos[1], size, \"transparent\", get_combo_color(skin, obj.combo_number, 1), radius * skin.approach_circle_width);\n backend.set_alpha(1);\n }\n\n private draw_hit_circle(obj: IHitObject, time: number): void {\n const { backend, skin, radius, fade_in, preempt } = this;\n\n const pos = (obj.data as { pos: Vec2 }).pos;\n const appear_time = obj.time - preempt;\n const hit_anim_duration = 240;\n\n // skip if not visible yet\n if (time < appear_time) return;\n // skip if hit animation is finished\n if (time > obj.end_time + hit_anim_duration) return;\n\n let opacity = 1;\n let scale = 1;\n\n // fade in phase\n if (time < obj.time) {\n if (has_mod(this.mods, Mods.Hidden)) {\n const hd_fade_in = this.preempt * 0.4;\n const fade_out_start = appear_time + hd_fade_in;\n const fade_out_duration = this.preempt * 0.3;\n\n if (time < fade_out_start) {\n opacity = clamp((time - appear_time) / hd_fade_in, 0, 1);\n } else {\n const fade_t = clamp((time - fade_out_start) / fade_out_duration, 0, 1);\n opacity = 1 - fade_t;\n }\n } else {\n opacity = clamp((time - appear_time) / this.fade_in, 0, 1);\n }\n }\n // hit animation phase (after hit time)\n else {\n // with HD, circle already faded - skip hit animation\n if (has_mod(this.mods, Mods.Hidden)) {\n return;\n }\n\n // skip hit animation if disabled\n if (!skin.enable_hit_animations) {\n return;\n }\n\n const t = clamp((time - obj.end_time) / hit_anim_duration, 0, 1);\n scale = 1 + (skin.hit_animation_scale - 1) * ease_out_cubic(t);\n opacity = 1 - ease_out_cubic(t);\n }\n\n if (opacity <= 0) return;\n\n const scaled_radius = radius * scale;\n const circle_size = scaled_radius * (1 - skin.circle_border_width / 2);\n const border_width = scaled_radius * skin.circle_border_width;\n\n backend.set_alpha(opacity * skin.hit_circle_opacity);\n\n backend.draw_circle(pos[0], pos[1], circle_size, get_combo_color(skin, obj.combo_number, 1), \"rgba(255,255,255,1)\", border_width);\n\n // only draw number before hit\n if (time < obj.time) {\n const font_size = radius * 0.8;\n const baseline_offset = font_size * 0.05;\n backend.draw_text(\n String(obj.combo_count),\n pos[0],\n pos[1] + baseline_offset,\n `600 ${font_size}px ${skin.font_family}`,\n \"rgba(255,255,255,1)\",\n \"center\",\n \"middle\"\n );\n }\n\n backend.set_alpha(1);\n }\n\n private draw_slider(obj: IHitObject, time: number): void {\n const { backend, skin, radius } = this;\n const data = obj.data as ISliderData;\n const path = data.computed_path;\n\n if (!path || path.length < 2) {\n return;\n }\n\n const body_opacity = this.get_slider_body_opacity(obj, time);\n\n if (body_opacity <= 0.01) {\n return;\n }\n\n const border_portion = 0.128;\n const body_radius = radius * (1 - border_portion);\n const combo_color = get_combo_color(skin, obj.combo_number, 1);\n\n // if using transparency, we need to mask out the border center to avoid it bleeding through\n if (skin.slider_body_opacity < 1 && skin.slider_border_opacity > 0) {\n this.draw_masked_slider(obj, path, combo_color, body_opacity, skin.slider_body_opacity, skin.slider_border_opacity);\n } else {\n // standard drawing (fast path)\n backend.save();\n\n // white border\n backend.set_alpha(body_opacity * skin.slider_border_opacity);\n backend.begin_path();\n backend.move_to(path[0][0], path[0][1]);\n\n for (let i = 1; i < path.length; i++) {\n backend.line_to(path[i][0], path[i][1]);\n }\n\n backend.stroke_path(\"rgba(255,255,255,1)\", radius * 2, \"round\", \"round\");\n\n // solid body color\n backend.set_alpha(body_opacity * skin.slider_body_opacity);\n backend.begin_path();\n backend.move_to(path[0][0], path[0][1]);\n\n for (let i = 1; i < path.length; i++) {\n backend.line_to(path[i][0], path[i][1]);\n }\n\n backend.stroke_path(combo_color, body_radius * 2, \"round\", \"round\");\n backend.restore();\n backend.set_alpha(body_opacity);\n }\n\n this.draw_slider_ticks(obj, data, path, time);\n\n if (data.repetitions > 1) {\n this.handle_reverse_arrows(obj, data, path, time);\n }\n\n const appear_time = obj.time - this.preempt;\n const HIT_ANIMATION_DURATION = 150;\n\n let head_opacity = 0;\n let head_scale = 1;\n\n if (has_mod(this.mods, Mods.Hidden)) {\n const hd_fade_in = this.preempt * 0.4;\n const fade_out_start = appear_time + hd_fade_in;\n const fade_out_duration = this.preempt * 0.3;\n\n if (time < appear_time) {\n head_opacity = 0;\n } else if (time < obj.time) {\n // fade in until hit time\n if (time < fade_out_start) {\n head_opacity = clamp((time - appear_time) / hd_fade_in, 0, 1);\n } else {\n const fade_t = clamp((time - fade_out_start) / fade_out_duration, 0, 1);\n head_opacity = 1 - fade_t;\n }\n } else if (time < obj.time + HIT_ANIMATION_DURATION) {\n // calculate opacity at hit time (obj.time)\n let opacity_at_hit = 0;\n if (obj.time < fade_out_start) {\n opacity_at_hit = clamp((obj.time - appear_time) / hd_fade_in, 0, 1);\n } else {\n const fade_t = clamp((obj.time - fade_out_start) / fade_out_duration, 0, 1);\n opacity_at_hit = 1 - fade_t;\n }\n\n // hit animation: fade out from current opacity\n const hit_progress = (time - obj.time) / HIT_ANIMATION_DURATION;\n head_opacity = opacity_at_hit * (1 - ease_out_cubic(hit_progress));\n head_scale = 1 + ease_out_cubic(hit_progress) * 0.4;\n }\n } else {\n if (time < appear_time) {\n head_opacity = 0;\n } else if (time < obj.time) {\n // fade in until hit time\n head_opacity = clamp((time - appear_time) / this.fade_in, 0, 1);\n } else if (time < obj.time + HIT_ANIMATION_DURATION) {\n // calculate opacity at hit time\n const opacity_at_hit = clamp((obj.time - appear_time) / this.fade_in, 0, 1);\n\n // hit animation: fade out + slight scale up\n const hit_progress = (time - obj.time) / HIT_ANIMATION_DURATION;\n head_opacity = opacity_at_hit * (1 - ease_out_cubic(hit_progress));\n head_scale = 1 + ease_out_cubic(hit_progress) * 0.4;\n }\n }\n\n if (head_opacity > 0) {\n const pos = data.pos;\n const circle_size = radius * (1 - skin.circle_border_width / 2) * head_scale;\n const border_width = radius * skin.circle_border_width * head_scale;\n\n backend.set_alpha(head_opacity * skin.hit_circle_opacity);\n\n backend.draw_circle(pos[0], pos[1], circle_size, get_combo_color(skin, obj.combo_number, 1), \"rgba(255,255,255,1)\", border_width);\n\n const font_size = radius * 0.8 * head_scale;\n const baseline_offset = font_size * 0.05;\n backend.draw_text(\n String(obj.combo_count),\n pos[0],\n pos[1] + baseline_offset,\n `600 ${font_size}px ${skin.font_family}`,\n \"rgba(255,255,255,1)\",\n \"center\",\n \"middle\"\n );\n }\n\n backend.set_alpha(1);\n }\n\n private handle_reverse_arrows(obj: IHitObject, data: ISliderData, path: Vec2[], time: number): void {\n const { radius, preempt, fade_in } = this;\n const appear_time = obj.time - preempt;\n const duration = data.duration!;\n\n // base opacity for arrows\n let base_opacity = 1.0;\n if (has_mod(this.mods, Mods.Hidden)) {\n const hd_fade_in = preempt * 0.4;\n const fade_out_start = appear_time + hd_fade_in;\n const fade_out_duration = preempt * 0.3;\n\n if (time < appear_time) {\n base_opacity = 0;\n } else if (time < fade_out_start) {\n base_opacity = clamp((time - appear_time) / hd_fade_in, 0, 1);\n } else {\n const fade_t = clamp((time - fade_out_start) / fade_out_duration, 0, 1);\n base_opacity = 1 - fade_t;\n }\n } else {\n if (time < appear_time) {\n base_opacity = 0;\n } else if (time < obj.time) {\n base_opacity = clamp((time - appear_time) / fade_in, 0, 1);\n }\n }\n\n if (base_opacity <= 0) return;\n\n const elapsed = Math.max(0, time - obj.time);\n const current_repeat = Math.floor(elapsed / duration);\n\n // draw reverse arrow at end of slider if there are remaining repeats\n const remaining_at_end = data.repetitions - 1 - current_repeat;\n if (remaining_at_end >= 1) {\n const at_end = current_repeat % 2 === 0;\n this.draw_reverse_arrow(path, at_end, time, base_opacity);\n }\n\n // draw both arrows before slider starts\n if (time < obj.time) {\n this.draw_reverse_arrow(path, true, time, base_opacity);\n if (data.repetitions > 2) {\n this.draw_reverse_arrow(path, false, time, base_opacity);\n }\n }\n }\n\n private draw_masked_slider(\n obj: IHitObject,\n path: Vec2[],\n combo_color: string,\n body_opacity: number,\n skin_body_opacity: number,\n skin_border_opacity: number\n ): void {\n const { backend, config, radius } = this;\n\n // check cache\n const cache = this.slider_cache.get(obj);\n\n // validate cache (must match current scale)\n if (cache && Math.abs(cache.scale - config.scale) < 0.001) {\n backend.save();\n if (config.scale !== 0) {\n backend.scale(1 / config.scale, 1 / config.scale);\n backend.translate(-config.offset_x, -config.offset_y);\n }\n\n const min_x = cache.image.min_x || 0;\n const min_y = cache.image.min_y || 0;\n const draw_x = Math.floor(min_x * config.scale + config.offset_x);\n const draw_y = Math.floor(min_y * config.scale + config.offset_y);\n\n backend.set_alpha(body_opacity);\n backend.draw_image(cache.image, draw_x, draw_y);\n backend.restore();\n return;\n }\n\n // cache miss, render to new canvas handle\n const image = backend.render_slider_to_image(path, radius, \"white\", combo_color, config.scale, skin_body_opacity, skin_border_opacity);\n if (!image) return;\n\n // cache it\n this.slider_cache.set(obj, {\n image,\n scale: config.scale\n });\n\n // draw immediately\n backend.save();\n if (config.scale !== 0) {\n backend.scale(1 / config.scale, 1 / config.scale);\n backend.translate(-config.offset_x, -config.offset_y);\n }\n\n const min_x = image.min_x || 0;\n const min_y = image.min_y || 0;\n const draw_x = Math.floor(min_x * config.scale + config.offset_x);\n const draw_y = Math.floor(min_y * config.scale + config.offset_y);\n\n backend.set_alpha(body_opacity);\n backend.draw_image(image, draw_x, draw_y);\n backend.restore();\n }\n\n private draw_slider_ticks(obj: IHitObject, data: ISliderData, path: Vec2[], time: number): void {\n const { backend, skin, radius, preempt, fade_in } = this;\n if (time > obj.end_time) return;\n\n const timing = this.get_timing_at(obj.time);\n const scoring_distance = 100 * this.beatmap.sv * timing.velocity;\n const velocity = scoring_distance / timing.beat_length;\n const tick_distance = scoring_distance / this.beatmap.tick_rate;\n const min_distance_from_end = velocity * 10;\n const slider_length = data.distance;\n const path_length = this.get_path_length(path);\n\n for (let d = tick_distance; d <= slider_length; d += tick_distance) {\n if (d >= slider_length - min_distance_from_end) break;\n\n const ratio = d / slider_length;\n const target_len = ratio * path_length;\n const pos = this.get_position_at_length(path, target_len);\n\n let opacity = 1.0;\n\n if (has_mod(this.mods, Mods.Hidden)) {\n const tick_time = obj.time + (d / slider_length) * data.duration!;\n const fade_out_time = tick_time - Math.min(1000, preempt * 0.7);\n const appear_time = tick_time - preempt;\n\n if (time < appear_time || time > fade_out_time) {\n opacity = 0;\n } else if (time > fade_out_time - 200) {\n opacity = (fade_out_time - time) / 200;\n } else {\n opacity = clamp((time - appear_time) / fade_in, 0, 1);\n }\n } else {\n const slider_appear_time = obj.time - preempt;\n if (time < slider_appear_time) {\n opacity = 0;\n } else {\n const base_fade = clamp((time - slider_appear_time) / fade_in, 0, 1);\n const position_delay = (d / slider_length) * (fade_in * 0.3);\n const adjusted_fade = clamp((time - slider_appear_time - position_delay) / (fade_in * 0.5), 0, 1);\n opacity = Math.min(base_fade, adjusted_fade);\n }\n\n const tick_time = obj.time + (d / slider_length) * data.duration!;\n if (time > tick_time) {\n const fade_t = (time - tick_time) / 150;\n opacity = Math.max(0, opacity * (1 - fade_t));\n }\n }\n\n if (opacity > 0) {\n backend.set_alpha(opacity * skin.slider_tick_opacity);\n backend.draw_circle(pos[0], pos[1], radius * skin.slider_tick_size, \"rgba(255,255,255,1)\", \"rgba(255,255,255,0.1)\", 1);\n }\n }\n }\n\n private get_position_at_length(path: Vec2[], target_length: number): Vec2 {\n let accumulated = 0;\n for (let i = 1; i < path.length; i++) {\n const segment_length = vec2_len(vec2_sub(path[i], path[i - 1]));\n if (accumulated + segment_length >= target_length) {\n const local_t = (target_length - accumulated) / segment_length;\n return vec2_lerp(path[i - 1], path[i], local_t);\n }\n accumulated += segment_length;\n }\n return path[path.length - 1];\n }\n\n private draw_reverse_arrow(path: Vec2[], at_end: boolean, time: number, opacity: number): void {\n const { backend, radius } = this;\n\n if (opacity <= 0) return;\n\n let pos: Vec2;\n let dir: Vec2;\n\n // get position and calculate direction from curve\n if (at_end) {\n pos = path[path.length - 1];\n // look backwards along the path for direction\n let aim_point = path[path.length - 1];\n for (let i = path.length - 2; i >= 0; i--) {\n const dx = path[i][0] - pos[0];\n const dy = path[i][1] - pos[1];\n if (dx * dx + dy * dy > 1) {\n aim_point = path[i];\n break;\n }\n }\n dir = vec2_normalize(vec2_sub(aim_point, pos));\n } else {\n pos = path[0];\n // look forwards along the path for direction\n let aim_point = path[0];\n for (let i = 1; i < path.length; i++) {\n const dx = path[i][0] - pos[0];\n const dy = path[i][1] - pos[1];\n if (dx * dx + dy * dy > 1) {\n aim_point = path[i];\n break;\n }\n }\n dir = vec2_normalize(vec2_sub(aim_point, pos));\n }\n\n // pulsing animation (osu! lazer style: 1.0 -> 1.3 over 300ms loop)\n const loop_duration = 300;\n const move_out_duration = 35;\n const move_in_duration = 250;\n const loop_time = time % loop_duration;\n\n let pulse_scale = 1.0;\n if (loop_time < move_out_duration) {\n pulse_scale = 1.0 + (loop_time / move_out_duration) * 0.3;\n } else {\n const t = (loop_time - move_out_duration) / move_in_duration;\n pulse_scale = 1.3 - t * 0.3;\n }\n\n const arrow_size = radius * 0.6 * pulse_scale;\n const angle = Math.atan2(dir[1], dir[0]);\n\n // draw chevron shape (like osu! lazer \">\") pointing in direction\n const chevron_spread = Math.PI / 3.5;\n const wing_len = arrow_size * 0.8;\n const tip_offset = arrow_size * 0.25;\n\n // tip of chevron offset from center\n const tip_x = pos[0] + Math.cos(angle) * tip_offset;\n const tip_y = pos[1] + Math.sin(angle) * tip_offset;\n\n // left and right wings\n const left_x = tip_x - Math.cos(angle - chevron_spread) * wing_len;\n const left_y = tip_y - Math.sin(angle - chevron_spread) * wing_len;\n const right_x = tip_x - Math.cos(angle + chevron_spread) * wing_len;\n const right_y = tip_y - Math.sin(angle + chevron_spread) * wing_len;\n\n backend.set_alpha(opacity);\n backend.begin_path();\n backend.move_to(left_x, left_y);\n backend.line_to(tip_x, tip_y);\n backend.line_to(right_x, right_y);\n backend.stroke_path(\"rgba(255,255,255,1)\", 3 * pulse_scale, \"round\", \"round\");\n backend.set_alpha(1);\n }\n\n private draw_follow_circle(obj: IHitObject, time: number): void {\n const { backend, skin, radius } = this;\n const data = obj.data as ISliderData;\n const duration = data.duration!;\n const total_duration = duration * data.repetitions;\n const elapsed = Math.min(time - obj.time, total_duration);\n const pos = this.get_slider_position(data, elapsed, duration);\n\n // slider ball should be visible during entire slider duration\n // follow circle can persist slightly after for fade out\n const after_end_delay = 240;\n if (time > obj.end_time + after_end_delay) return;\n\n // pulsing animation while holding slider\n const pulse_speed = 0.008;\n const pulse = 1 + Math.sin(time * pulse_speed) * 0.08;\n\n // follow circle should grow in at start\n let scale_factor = 1.0;\n const GROW_DURATION = 100;\n\n if (elapsed < GROW_DURATION) {\n const t = clamp(elapsed / GROW_DURATION, 0, 1);\n scale_factor = 0.5 + t * 0.5;\n }\n\n let follow_opacity = skin.follow_circle_opacity;\n\n // Hidden mod: follow circle (ball + ring) should fade out\n if (has_mod(this.mods, Mods.Hidden)) {\n const appear_time = obj.time - this.preempt;\n const hd_fade_in = this.preempt * 0.4;\n const fade_out_start = appear_time + hd_fade_in;\n const fade_out_duration = this.preempt * 0.3;\n\n if (time < fade_out_start) {\n follow_opacity *= clamp((time - appear_time) / hd_fade_in, 0, 1);\n } else {\n const fade_t = clamp((time - fade_out_start) / fade_out_duration, 0, 1);\n follow_opacity *= 1 - fade_t;\n }\n }\n\n // fade out and scale out after slider ends\n if (time > obj.end_time) {\n const out_t = clamp((time - obj.end_time) / 240, 0, 1);\n follow_opacity *= 1 - out_t;\n scale_factor *= 1 + out_t * 0.3; // expand more for \"wow\" effect\n }\n\n if (follow_opacity <= 0) return;\n\n // draw slider ball (inner circle at slider position)\n if (skin.enable_slider_ball) {\n const ball_size = radius * 0.85; // ball doesn't expand, only the ring does\n\n // ball fades out quickly after slider ends (100ms)\n let ball_alpha = follow_opacity * (skin.slider_ball_opacity / skin.follow_circle_opacity);\n if (time > obj.end_time) {\n const ball_out_t = clamp((time - obj.end_time) / 100, 0, 1);\n ball_alpha *= 1 - ball_out_t;\n }\n\n if (ball_alpha > 0) {\n backend.set_alpha(ball_alpha);\n backend.draw_circle(pos[0], pos[1], ball_size, get_combo_color(skin, obj.combo_number, 0.7), \"rgba(255,255,255,0.9)\", radius * 0.12);\n }\n }\n\n // draw follow circle (outer ring with pulse)\n const follow_size = radius * skin.follow_circle_factor * pulse * scale_factor;\n const ring_color = skin.follow_circle_use_combo_color ? get_combo_color(skin, obj.combo_number, 1.0) : skin.follow_circle_color;\n\n // ring should NOT fade out in HD, just like the slider ball\n backend.set_alpha(follow_opacity);\n backend.begin_path();\n backend.arc_to(pos[0], pos[1], follow_size, 0, Math.PI * 2);\n backend.stroke_path(ring_color, skin.follow_circle_width);\n\n backend.set_alpha(1);\n }\n\n private get_slider_position(slider: ISliderData, elapsed: number, duration: number): Vec2 {\n const path = slider.computed_path;\n if (!path || path.length === 0) return slider.pos;\n\n const repeat_time = elapsed % (duration * 2);\n let t = repeat_time < duration ? repeat_time / duration : 2 - repeat_time / duration;\n\n t = clamp(t, 0, 1);\n\n const total_length = this.get_path_length(path);\n const target_length = t * total_length;\n\n let accumulated = 0;\n for (let i = 1; i < path.length; i++) {\n const segment_length = vec2_len(vec2_sub(path[i], path[i - 1]));\n\n if (accumulated + segment_length >= target_length) {\n const local_t = (target_length - accumulated) / segment_length;\n return vec2_lerp(path[i - 1], path[i], local_t);\n }\n\n accumulated += segment_length;\n }\n\n return path[path.length - 1];\n }\n\n private get_path_length(path: Vec2[]): number {\n let length = 0;\n for (let i = 1; i < path.length; i++) {\n length += vec2_len(vec2_sub(path[i], path[i - 1]));\n }\n return length;\n }\n\n private draw_spinner(obj: IHitObject, time: number): void {\n const { backend, skin } = this;\n // Spinners should NOT be affected by Hidden mod\n const appear_time = obj.time - this.preempt;\n if (time < appear_time) return;\n\n let opacity = clamp((time - appear_time) / this.fade_in, 0, 1);\n if (time > obj.end_time) {\n const fade_t = clamp((time - obj.end_time) / 200, 0, 1);\n opacity = 1 - ease_out_cubic(fade_t);\n }\n\n if (opacity <= 0) return;\n\n const x = 256;\n const y = 192;\n const duration = obj.end_time - obj.time;\n const progress = clamp((time - obj.time) / duration, 0, 1);\n\n backend.set_alpha(opacity);\n\n const approach_size = skin.spinner_size * (1 - progress);\n if (approach_size > 5) {\n backend.begin_path();\n backend.arc_to(x, y, approach_size, 0, Math.PI * 2);\n backend.stroke_path(\"rgba(255,255,255,0.6)\", 4);\n }\n\n backend.draw_circle(x, y, skin.spinner_size, \"rgba(0,0,0,0.2)\");\n backend.draw_circle(x, y, 12, \"white\");\n }\n\n private draw_follow_point(prev: IHitObject, next: IHitObject, time: number): void {\n if (has_mod(this.mods, Mods.Hidden)) return;\n if (prev.combo_number !== next.combo_number) return;\n\n const { backend, skin } = this;\n\n if (time < prev.end_time || time > next.time) return;\n\n const start_pos = prev.end_pos;\n const end_pos = (next.data as { pos: Vec2 }).pos;\n\n const dx = end_pos[0] - start_pos[0];\n const dy = end_pos[1] - start_pos[1];\n const distance = Math.sqrt(dx * dx + dy * dy);\n if (distance < 48) return;\n\n const duration = next.time - prev.end_time;\n const progress = (time - prev.end_time) / duration;\n let opacity = 1.0;\n\n if (progress < 0.2) {\n opacity = progress / 0.2;\n }\n if (progress > 0.8) {\n opacity = (1 - progress) / 0.2;\n }\n\n if (opacity <= 0) return;\n\n const line_progress = clamp(progress * 1.5, 0, 1);\n const line_start_x = lerp(start_pos[0], end_pos[0], Math.max(0, progress - 0.3));\n const line_start_y = lerp(start_pos[1], end_pos[1], Math.max(0, progress - 0.3));\n const line_end_x = lerp(start_pos[0], end_pos[0], line_progress);\n const line_end_y = lerp(start_pos[1], end_pos[1], line_progress);\n\n backend.set_alpha(opacity * 0.6);\n backend.begin_path();\n backend.move_to(line_start_x, line_start_y);\n backend.line_to(line_end_x, line_end_y);\n backend.stroke_path(\"rgba(255,255,255,1)\", skin.follow_point_width, \"round\", \"round\");\n backend.set_alpha(1);\n }\n}\n",
|
|
23
|
-
"import type { IBeatmap, IHitObject, IHoldData } from \"../../types/beatmap\";\nimport { is_hold } from \"../../types/beatmap\";\nimport { Mods, has_mod } from \"../../types/mods\";\nimport { get_rate_multiplier } from \"../../mods\";\nimport { BaseRenderer, type IRendererConfig, DEFAULT_RENDERER_CONFIG, PLAYFIELD_WIDTH, PLAYFIELD_HEIGHT } from \"../base_renderer\";\nimport type { IRenderBackend, RenderImage } from \"../backend/render_backend\";\nimport type { ISkinConfig } from \"../../skin/skin_config\";\nimport { get_mania_lane_color } from \"../../skin/skin_config\";\n\n// lazer scroll time constants (DrawableManiaRuleset.cs)\nconst MAX_TIME_RANGE = 11485;\nconst BASE_SCROLL_SPEED = 20;\n\nexport class ManiaRenderer extends BaseRenderer {\n private key_count: number = 4;\n private scroll_time: number = MAX_TIME_RANGE / BASE_SCROLL_SPEED;\n\n // overlay constants (configurable)\n private hd_coverage: number = 0.25; // bottom 25% for hidden\n private fi_coverage: number = 0.6; // top 60% for fade-in\n private gradient_ratio: number = 0.2; // fade region is 20% of playfield height\n\n constructor(backend: IRenderBackend, skin: ISkinConfig, mods: number = 0, config: IRendererConfig = DEFAULT_RENDERER_CONFIG) {\n super(backend, skin, mods, config);\n this.update_scroll_time();\n }\n\n initialize(beatmap: IBeatmap): void {\n this.beatmap = beatmap;\n this.objects = [...beatmap.objects];\n this.key_count = Math.floor(beatmap.cs);\n\n for (const obj of this.objects) {\n if (is_hold(obj)) {\n obj.end_time = (obj.data as IHoldData).end_time;\n }\n }\n }\n\n set_mods(mods: number): void {\n this.mods = mods;\n this.update_scroll_time();\n }\n\n private update_scroll_time(): void {\n const rate = get_rate_multiplier(this.mods);\n this.scroll_time = MAX_TIME_RANGE / (BASE_SCROLL_SPEED * rate);\n }\n\n private time_to_y(time_diff: number): number {\n const hit_pos = this.skin.mania_hit_position;\n const progress = time_diff / this.scroll_time;\n return hit_pos - progress * hit_pos;\n }\n\n render(time: number): void {\n const { backend, config, skin, key_count } = this;\n\n this.render_background();\n\n const total_width = key_count * skin.mania_lane_width;\n const x_offset = Math.floor((PLAYFIELD_WIDTH - total_width) / 2);\n const hit_pos = skin.mania_hit_position;\n\n backend.save();\n backend.translate(config.offset_x, config.offset_y);\n backend.scale(config.scale, config.scale);\n\n this.render_playfield(total_width, PLAYFIELD_HEIGHT, x_offset);\n\n // draw lane keys at judgment line\n this.draw_lane_keys(time, x_offset);\n this.draw_judgment_line(x_offset);\n\n // clip notes to playfield above judgment line\n backend.save();\n backend.begin_path();\n backend.rect(x_offset, 0, total_width, hit_pos);\n backend.clip();\n\n // dim background for lanes\n backend.set_alpha(0.7);\n backend.draw_rect(x_offset, 0, total_width, hit_pos, \"#000000\");\n backend.set_alpha(1);\n\n // draw visible objects (those that haven't ended yet)\n for (const obj of this.objects) {\n if (obj.end_time < time) {\n continue;\n }\n\n if (is_hold(obj)) {\n this.draw_hold_note(obj, time, x_offset);\n } else {\n this.draw_note(obj, time, x_offset);\n }\n }\n\n // draw cover overlay for hd/fadein\n if (has_mod(this.mods, Mods.Hidden) || has_mod(this.mods, Mods.FadeIn)) {\n const coverage_ratio = has_mod(this.mods, Mods.Hidden) ? this.hd_coverage : this.fi_coverage;\n const total_h = hit_pos * coverage_ratio;\n const grad_h = hit_pos * this.gradient_ratio;\n\n if (has_mod(this.mods, Mods.Hidden)) {\n const start_y = hit_pos - total_h;\n const fade_end = grad_h / total_h;\n\n const gradient = backend.create_linear_gradient(x_offset, start_y, x_offset, hit_pos, [\n { offset: 0.0, color: \"rgba(0,0,0,0)\" },\n { offset: fade_end * 0.4, color: \"rgba(0,0,0,0.3)\" },\n { offset: fade_end * 0.7, color: \"rgba(0,0,0,0.75)\" },\n { offset: fade_end * 0.9, color: \"rgba(0,0,0,0.95)\" },\n { offset: fade_end, color: \"rgba(0,0,0,1)\" },\n { offset: 1.0, color: \"rgba(0,0,0,1)\" }\n ]);\n backend.draw_rect_gradient(x_offset, start_y, total_width, total_h, gradient);\n } else {\n const fade_start = (total_h - grad_h) / total_h;\n const gradient = backend.create_linear_gradient(x_offset, 0, x_offset, total_h, [\n { offset: 0.0, color: \"rgba(0,0,0,1)\" },\n { offset: fade_start, color: \"rgba(0,0,0,1)\" },\n { offset: fade_start + (1 - fade_start) * 0.1, color: \"rgba(0,0,0,0.95)\" },\n { offset: fade_start + (1 - fade_start) * 0.4, color: \"rgba(0,0,0,0.75)\" },\n { offset: fade_start + (1 - fade_start) * 0.7, color: \"rgba(0,0,0,0.3)\" },\n { offset: 1.0, color: \"rgba(0,0,0,0)\" }\n ]);\n backend.draw_rect_gradient(x_offset, 0, total_width, total_h, gradient);\n }\n }\n backend.restore();\n backend.restore();\n }\n\n private get_lane(obj: IHitObject): number {\n const pos = (obj.data as { pos: [number, number] }).pos;\n let lane = Math.floor((pos[0] * this.key_count) / 512);\n\n if (has_mod(this.mods, Mods.Mirror)) {\n lane = this.key_count - 1 - lane;\n }\n\n return lane;\n }\n\n private draw_note(obj: IHitObject, time: number, x_offset: number): void {\n const { backend, skin, key_count } = this;\n const lane = this.get_lane(obj);\n\n const lane_width = skin.mania_lane_width;\n const note_height = skin.mania_note_height;\n const spacing = skin.mania_lane_spacing;\n\n // calculate Y position from time difference\n const time_diff = obj.time - time;\n const y = this.time_to_y(time_diff);\n\n // skip if note is too far above screen\n if (y < -note_height - 64) {\n return;\n }\n\n const x = x_offset + lane * lane_width;\n const color = get_mania_lane_color(skin, key_count, lane);\n\n backend.set_alpha(1.0);\n backend.draw_rect(x + spacing, y - note_height, lane_width - 2 * spacing, note_height, color);\n }\n\n private draw_hold_note(obj: IHitObject, time: number, x_offset: number): void {\n const { backend, skin, key_count } = this;\n const data = obj.data as IHoldData;\n const lane = this.get_lane(obj);\n\n const lane_width = skin.mania_lane_width;\n const note_height = skin.mania_note_height;\n const spacing = skin.mania_lane_spacing;\n\n // calculate head and tail Y positions\n const head_time_diff = obj.time - time;\n const tail_time_diff = data.end_time - time;\n\n const head_y = this.time_to_y(head_time_diff);\n const tail_y = this.time_to_y(tail_time_diff);\n\n const x = x_offset + lane * lane_width;\n const color = get_mania_lane_color(skin, key_count, lane);\n\n // skip if entirely off screen\n if (tail_y < -64 && head_y < -64) {\n return;\n }\n\n // draw body (from tail to judgment line or head, whichever is lower)\n const body_top = tail_y;\n const body_bottom = head_time_diff < 0 ? skin.mania_hit_position : head_y;\n const body_height = body_bottom - body_top;\n\n if (body_height > 0) {\n backend.set_alpha(0.9);\n backend.draw_rect(x + spacing, body_top, lane_width - 2 * spacing, body_height, color);\n }\n\n // only draw head if not yet hit (before hit time)\n if (head_time_diff >= 0) {\n backend.set_alpha(1.0);\n backend.draw_rect(x + spacing, head_y - note_height, lane_width - 2 * spacing, note_height, color);\n }\n\n backend.set_alpha(1); // reset after hold note\n }\n\n private draw_judgment_line(x_offset: number): void {\n const { backend, skin, key_count } = this;\n const lane_width = skin.mania_lane_width;\n const hit_pos = skin.mania_hit_position;\n\n backend.draw_rect(x_offset, hit_pos - 1, lane_width * key_count, 2, \"#ffffff\");\n }\n\n private draw_lane_keys(time: number, x_offset: number): void {\n const { backend, skin, key_count } = this;\n const { mania_lane_width: lane_width, mania_hit_position: hit_pos, mania_lane_spacing: spacing, mania_note_height: note_height } = skin;\n const key_height = note_height + 5;\n\n const pressed = new Set<number>();\n const HIT_WINDOW = 50;\n\n for (const obj of this.objects) {\n if (time >= obj.time - HIT_WINDOW && time <= obj.end_time + HIT_WINDOW) {\n pressed.add(this.get_lane(obj));\n }\n }\n\n for (let i = 0; i < key_count; i++) {\n const is_pressed = pressed.has(i);\n const x = x_offset + i * lane_width;\n const color = get_mania_lane_color(skin, key_count, i);\n\n backend.set_alpha(0.3);\n backend.draw_rect(x + spacing, hit_pos, lane_width - 2 * spacing, key_height, color);\n\n if (is_pressed) {\n backend.set_alpha(1.0);\n backend.draw_rect(x + spacing, hit_pos, lane_width - 2 * spacing, key_height, \"#ff6666\");\n }\n }\n\n backend.set_alpha(1);\n }\n}\n",
|
|
24
|
-
"import {
|
|
22
|
+
"export interface ISkinConfig {\n combo_colors: string[];\n\n // circle rendering\n circle_border_width: number;\n hit_circle_opacity: number;\n\n // approach circle\n enable_approach_circle: boolean;\n approach_circle_width: number;\n approach_circle_opacity: number;\n approach_circle_use_combo_color: boolean;\n approach_circle_color?: string;\n\n // hit glow effect\n enable_glow: boolean;\n glow_color?: string;\n glow_use_combo_color: boolean;\n glow_opacity: number;\n\n // hit explode/flash effect (after hit)\n enable_hit_explode: boolean;\n\n // slider rendering\n slider_body_opacity: number;\n slider_border_opacity: number;\n slider_tick_opacity: number;\n slider_tick_size: number;\n slider_border_color?: string;\n slider_track_override?: string;\n\n // follow circle (slider ball outer ring)\n follow_circle_factor: number;\n follow_circle_width: number;\n follow_circle_opacity: number;\n follow_circle_color: string;\n follow_circle_use_combo_color: boolean;\n\n // slider ball (inner circle)\n slider_ball_color: string;\n slider_ball_opacity: number;\n enable_slider_ball: boolean;\n\n // follow points (dots between objects)\n follow_point_width: number;\n\n // spinner\n spinner_size: number;\n spinner_center_size: number;\n\n // mania\n mania_lane_width: number;\n mania_note_height: number;\n mania_hit_position: number;\n mania_lane_spacing: number;\n mania_lane_colors: Record<number, string[]>;\n\n // general\n font_family: string;\n hit_animation_duration: number;\n hit_animation_scale: number;\n\n // animation toggles\n enable_hit_animations: boolean;\n enable_follow_circle_animations: boolean;\n}\n\nconst MANIA_KEY_COLORS: Record<number, string[]> = {\n 1: [\"#d5bc00\"],\n 2: [\"#ffffff\", \"#ffffff\"],\n 3: [\"#ffffff\", \"#d5bc00\", \"#ffffff\"],\n 4: [\"#ffffff\", \"#dc8dba\", \"#dc8dba\", \"#ffffff\"],\n 5: [\"#ffffff\", \"#dc8dba\", \"#d5bc00\", \"#dc8dba\", \"#ffffff\"],\n 6: [\"#ffffff\", \"#dc8dba\", \"#ffffff\", \"#ffffff\", \"#dc8dba\", \"#ffffff\"],\n 7: [\"#ffffff\", \"#dc8dba\", \"#ffffff\", \"#d5bc00\", \"#ffffff\", \"#dc8dba\", \"#ffffff\"],\n 8: [\"#d5bc00\", \"#ffffff\", \"#dc8dba\", \"#ffffff\", \"#d5bc00\", \"#ffffff\", \"#dc8dba\", \"#ffffff\"],\n 9: [\"#ffffff\", \"#dc8dba\", \"#ffffff\", \"#dc8dba\", \"#d5bc00\", \"#dc8dba\", \"#ffffff\", \"#dc8dba\", \"#ffffff\"],\n 10: [\"#ffffff\", \"#dc8dba\", \"#d5bc00\", \"#dc8dba\", \"#ffffff\", \"#ffffff\", \"#dc8dba\", \"#d5bc00\", \"#dc8dba\", \"#ffffff\"]\n};\n\nexport const DEFAULT_SKIN: ISkinConfig = {\n combo_colors: [\"0,185,0\", \"7, 105, 227\", \"224, 4, 38\", \"227, 171, 2\"],\n\n circle_border_width: 0.12,\n hit_circle_opacity: 0.95,\n\n enable_approach_circle: true,\n approach_circle_width: 0.1,\n approach_circle_opacity: 0.5,\n approach_circle_use_combo_color: true,\n\n enable_glow: false,\n glow_use_combo_color: true,\n glow_opacity: 0.3,\n\n enable_hit_explode: true,\n\n slider_body_opacity: 0.9,\n slider_border_opacity: 1.0,\n slider_tick_opacity: 0.75,\n slider_tick_size: 0.1,\n\n follow_circle_factor: 1.5,\n follow_circle_width: 4,\n follow_circle_opacity: 0.5,\n follow_circle_color: \"#d3d3d3ff\",\n follow_circle_use_combo_color: false,\n\n slider_ball_color: \"#ffffff\",\n slider_ball_opacity: 1.0,\n enable_slider_ball: true,\n\n follow_point_width: 2,\n\n spinner_size: 180,\n spinner_center_size: 10,\n\n mania_lane_width: 30,\n mania_note_height: 15,\n mania_hit_position: 364,\n mania_lane_spacing: 1,\n mania_lane_colors: MANIA_KEY_COLORS,\n\n font_family: '\"Exo 2\", sans-serif',\n hit_animation_duration: 300,\n hit_animation_scale: 1.3,\n\n enable_hit_animations: true,\n enable_follow_circle_animations: true\n};\n\nexport const merge_skin = (partial?: Partial<ISkinConfig>): ISkinConfig => {\n if (!partial) return { ...DEFAULT_SKIN };\n\n return {\n ...DEFAULT_SKIN,\n ...partial,\n mania_lane_colors: partial.mania_lane_colors ? { ...MANIA_KEY_COLORS, ...partial.mania_lane_colors } : MANIA_KEY_COLORS\n };\n};\n\nexport const get_combo_color = (skin: ISkinConfig, combo_number: number, alpha: number = 1): string => {\n const color = skin.combo_colors[combo_number % skin.combo_colors.length];\n return `rgba(${color},${alpha})`;\n};\n\nexport const get_mania_lane_color = (skin: ISkinConfig, key_count: number, lane: number): string => {\n const colors = skin.mania_lane_colors[key_count] ?? skin.mania_lane_colors[4];\n return colors[lane % colors.length] ?? \"#ffffff\";\n};\n",
|
|
23
|
+
"export type EasingFunction = (t: number) => number;\n\nexport const Easing = {\n None: (t: number) => t,\n Out: (t: number) => 1 - Math.pow(1 - t, 2),\n In: (t: number) => t * t,\n InOut: (t: number) => (t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2),\n OutCubic: (t: number) => 1 - Math.pow(1 - t, 3),\n InCubic: (t: number) => t * t * t,\n OutQuad: (t: number) => 1 - Math.pow(1 - t, 2),\n InQuad: (t: number) => t * t,\n OutQuint: (t: number) => 1 - Math.pow(1 - t, 5),\n InQuint: (t: number) => t * t * t * t * t,\n OutElastic: (t: number) => {\n const c4 = (2 * Math.PI) / 3;\n return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;\n }\n};\n\nexport interface Transform {\n property: \"alpha\" | \"scale\" | \"x\" | \"y\" | \"rotation\";\n start_value: number;\n end_value: number;\n start_time: number;\n end_time: number;\n easing: EasingFunction;\n loop?: boolean;\n loop_delay?: number;\n}\n\nexport class TransformSequence {\n private transforms: Transform[] = [];\n\n add(\n property: Transform[\"property\"],\n start_value: number,\n end_value: number,\n start_time: number,\n duration: number,\n easing: EasingFunction = Easing.None\n ): this {\n this.transforms.push({\n property,\n start_value,\n end_value,\n start_time,\n end_time: start_time + duration,\n easing\n });\n return this;\n }\n\n then(): this {\n return this;\n }\n\n get_value(property: Transform[\"property\"], time: number, default_value: number): number {\n let value = default_value;\n\n for (const t of this.transforms) {\n if (t.property !== property) continue;\n if (time < t.start_time) continue;\n\n if (time >= t.end_time) {\n value = t.end_value;\n } else {\n const progress = (time - t.start_time) / (t.end_time - t.start_time);\n const eased = t.easing(progress);\n value = t.start_value + (t.end_value - t.start_value) * eased;\n }\n }\n\n return value;\n }\n\n clear(): void {\n this.transforms = [];\n }\n}\n",
|
|
24
|
+
"import type { IRenderBackend } from \"../backend/render_backend\";\nimport type { IHitObject } from \"../../types/beatmap\";\nimport type { ISkinConfig } from \"../../skin/skin_config\";\nimport { TransformSequence, Easing } from \"./transforms\";\n\nexport enum ArmedState {\n Idle,\n Hit,\n Miss\n}\n\nexport interface DrawableConfig {\n backend: IRenderBackend;\n skin: ISkinConfig;\n preempt: number;\n fade_in: number;\n radius: number;\n scale?: number;\n mods: number;\n}\n\nexport abstract class Drawable {\n protected backend: IRenderBackend;\n protected skin: ISkinConfig;\n\n protected hit_object: IHitObject;\n protected config: DrawableConfig;\n\n protected alpha = 1;\n protected scale = 1;\n protected rotation = 0;\n protected x = 0;\n protected y = 0;\n\n protected armed_state = ArmedState.Idle;\n protected transforms = new TransformSequence();\n\n protected life_time_start = 0;\n protected life_time_end = 0;\n\n constructor(hit_object: IHitObject, config: DrawableConfig) {\n this.hit_object = hit_object;\n this.config = config;\n this.backend = config.backend;\n this.skin = config.skin;\n\n const data = hit_object.data as { pos: [number, number] };\n this.x = data.pos[0];\n this.y = data.pos[1];\n\n this.apply_defaults();\n }\n\n protected apply_defaults(): void {\n const { hit_object, config } = this;\n const appear_time = hit_object.time - config.preempt;\n\n this.life_time_start = appear_time;\n this.life_time_end = hit_object.end_time + 800;\n }\n\n is_alive(time: number): boolean {\n return time >= this.life_time_start && time <= this.life_time_end;\n }\n\n update(time: number): void {\n this.alpha = this.transforms.get_value(\"alpha\", time, 1);\n this.scale = this.transforms.get_value(\"scale\", time, 1);\n this.rotation = this.transforms.get_value(\"rotation\", time, 0);\n\n this.update_state(time);\n }\n\n protected update_state(time: number): void {\n if (this.armed_state === ArmedState.Idle && time >= this.hit_object.time) {\n this.armed_state = ArmedState.Hit;\n this.on_hit(time);\n }\n }\n\n protected on_hit(time: number): void {\n // override in subclasses\n }\n\n abstract render(time: number): void;\n\n // multi-pass rendering support\n render_body_pass(time: number): void {}\n render_head_pass(time: number): void {}\n\n get start_time(): number {\n return this.hit_object.time;\n }\n\n get end_time(): number {\n return this.hit_object.end_time;\n }\n\n get combo_number(): number {\n return this.hit_object.combo_number ?? 0;\n }\n\n get combo_count(): number {\n return this.hit_object.combo_count ?? 1;\n }\n\n get position(): [number, number] {\n return [this.x, this.y];\n }\n}\n",
|
|
25
|
+
"import type { IHitObject } from \"../../types/beatmap\";\nimport { Drawable, type DrawableConfig } from \"./drawable\";\nimport { Easing } from \"./transforms\";\nimport { get_combo_color } from \"../../skin/skin_config\";\nimport { clamp } from \"../../math/vector2\";\nimport { Mods, has_mod } from \"../../types/mods\";\n\nexport class DrawableHitCircle extends Drawable {\n private circle_alpha = 0;\n private circle_scale = 1;\n private approach_alpha = 0;\n private approach_scale = 4;\n\n private flash_alpha = 0;\n private explode_alpha = 0;\n\n constructor(hit_object: IHitObject, config: DrawableConfig) {\n super(hit_object, config);\n }\n\n update(time: number): void {\n super.update(time);\n this.calculate_animations(time);\n }\n\n private calculate_animations(time: number): void {\n const { config, hit_object } = this;\n const appear_time = hit_object.time - config.preempt;\n const hit_time = hit_object.time;\n\n // reset all\n this.flash_alpha = 0;\n this.explode_alpha = 0;\n\n if (time < appear_time) {\n this.circle_alpha = 0;\n this.circle_scale = 1;\n this.approach_alpha = 0;\n this.approach_scale = 4;\n return;\n }\n\n // approach phase (before hit)\n if (time < hit_time) {\n // circle: simple fade in over fade_in duration\n let alpha = clamp((time - appear_time) / config.fade_in, 0, 1);\n\n // HD mod: fade out before hit\n if (has_mod(config.mods, Mods.Hidden)) {\n const fade_out_start = hit_time - config.preempt * 0.4;\n const fade_out_duration = config.preempt * 0.3;\n\n if (time > fade_out_start) {\n const fade_out_progress = clamp((time - fade_out_start) / fade_out_duration, 0, 1);\n alpha *= 1 - fade_out_progress;\n }\n }\n\n this.circle_alpha = alpha;\n this.circle_scale = 1;\n\n // approach circle calculation disabled as it is handled by renderer (and hidden in HD)\n this.approach_alpha = 0;\n this.approach_scale = 1;\n return;\n }\n\n // after hit time - hit animations\n const elapsed = time - hit_time;\n\n const FLASH_IN = 40;\n const FLASH_OUT = 100;\n const SCALE_DURATION = 400;\n const FADE_OUT = 240;\n\n // approach circle: quick fadeout (50ms)\n this.approach_alpha = 0.9 * (1 - clamp(elapsed / 50, 0, 1));\n this.approach_scale = 1;\n\n // flash: fadeto 0.8 in 40ms, then fadeout 100ms\n if (elapsed < FLASH_IN) {\n this.flash_alpha = 0.8 * (elapsed / FLASH_IN);\n } else if (elapsed < FLASH_IN + FLASH_OUT) {\n this.flash_alpha = 0.8 * (1 - (elapsed - FLASH_IN) / FLASH_OUT);\n }\n\n // explode: fadein over 40ms, then fades out\n if (elapsed < FLASH_IN) {\n this.explode_alpha = elapsed / FLASH_IN;\n } else {\n this.explode_alpha = 1 - clamp((elapsed - FLASH_IN) / (FADE_OUT * 2), 0, 1);\n }\n\n // scale: 1 - 1.4 over scale duration with OutQuad\n const scale_progress = clamp(elapsed / SCALE_DURATION, 0, 1);\n this.circle_scale = 1 + 0.4 * Easing.OutQuad(scale_progress);\n\n // circle: fade out over FADE_OUT duration while scaling\n this.circle_alpha = 1 - clamp(elapsed / FADE_OUT, 0, 1);\n }\n\n render(time: number): void {\n const { backend, skin, config, hit_object } = this;\n const { radius } = config;\n const pos = this.position;\n const combo_color = get_combo_color(skin, this.combo_number, 1);\n\n // early exit if nothing to draw\n if (this.circle_alpha <= 0 && this.approach_alpha <= 0 && this.flash_alpha <= 0 && this.explode_alpha <= 0) {\n return;\n }\n\n const scaled_radius = radius * this.circle_scale;\n\n // circle (before hit)\n if (this.circle_alpha > 0.01) {\n const border_width = radius * skin.circle_border_width;\n const inner_radius = radius * (1 - skin.circle_border_width / 2);\n\n backend.set_alpha(this.circle_alpha * skin.hit_circle_opacity);\n\n // main circle fill\n backend.draw_circle(pos[0], pos[1], inner_radius, combo_color, \"rgba(255,255,255,1)\", border_width);\n\n // combo number\n const font_size = radius * 0.8;\n backend.draw_text(\n String(this.combo_count),\n pos[0],\n pos[1] + font_size * 0.05,\n `600 ${font_size}px ${skin.font_family}`,\n \"rgba(255,255,255,1)\",\n \"center\",\n \"middle\"\n );\n\n backend.set_alpha(1);\n }\n\n // flash (white burst, additive)\n if (skin.enable_hit_explode && this.flash_alpha > 0.01) {\n backend.save();\n backend.set_blend_mode(\"lighter\");\n backend.set_alpha(this.flash_alpha);\n backend.draw_circle(pos[0], pos[1], scaled_radius, \"rgba(255,255,255,1)\", \"transparent\", 0);\n backend.restore();\n }\n\n // explode (colored burst, additive)\n if (skin.enable_hit_explode && this.explode_alpha > 0.01) {\n backend.save();\n backend.set_blend_mode(\"lighter\");\n backend.set_alpha(this.explode_alpha * 0.15);\n backend.draw_circle(pos[0], pos[1], scaled_radius * 1.2, combo_color, \"transparent\", 0);\n backend.restore();\n }\n }\n}\n",
|
|
26
|
+
"import type { IHitObject, ISliderData } from \"../../types/beatmap\";\nimport type { RenderImage } from \"../backend/render_backend\";\nimport { Drawable, type DrawableConfig } from \"./drawable\";\nimport { Easing } from \"./transforms\";\nimport { get_combo_color } from \"../../skin/skin_config\";\nimport { clamp, vec2_len, vec2_sub, vec2_lerp, type Vec2 } from \"../../math/vector2\";\nimport { Mods, has_mod } from \"../../types/mods\";\n\nconst FADE_OUT_DURATION = 240;\nconst HEAD_ANIM_DURATION = 150;\nconst ARROW_SCALE_AMOUNT = 1.3;\nconst ARROW_MOVE_OUT_DURATION = 35;\nconst ARROW_MOVE_IN_DURATION = 250;\nconst ARROW_TOTAL_CYCLE = 300;\n\ninterface SliderTick {\n pos: Vec2;\n time: number;\n span_index: number;\n path_progress: number;\n}\n\ninterface SliderRepeat {\n pos: Vec2;\n time: number;\n repeat_index: number;\n path_progress: number;\n}\n\nexport class DrawableSlider extends Drawable {\n private slider_data: ISliderData;\n private path: Vec2[];\n private path_length: number;\n private span_duration: number;\n\n private body_alpha = 0;\n private head_alpha = 0;\n private head_scale = 1;\n private ball_alpha = 0;\n private ball_position: Vec2;\n private follow_alpha = 0;\n private follow_scale = 1;\n\n private ticks: SliderTick[] = [];\n private repeats: SliderRepeat[] = [];\n private tick_distance: number;\n private cached_texture: RenderImage | null = null;\n\n constructor(hit_object: IHitObject, config: DrawableConfig, path: Vec2[], span_duration: number, tick_distance: number) {\n super(hit_object, config);\n this.slider_data = hit_object.data as ISliderData;\n this.path = path;\n this.span_duration = span_duration;\n this.tick_distance = tick_distance;\n this.path_length = this.calculate_path_length();\n this.ball_position = this.slider_data.pos;\n\n this.generate_nested_objects();\n\n this.life_time_end = hit_object.end_time + FADE_OUT_DURATION;\n }\n\n private generate_nested_objects(): void {\n this.ticks = [];\n this.repeats = [];\n\n const { slider_data, path_length, span_duration, hit_object, tick_distance } = this;\n const span_count = slider_data.repetitions;\n\n if (tick_distance <= 0 || path_length <= 0) return;\n\n const velocity = path_length / span_duration;\n const min_distance_from_end = velocity * 10;\n\n // generate repeats\n for (let span = 0; span < span_count - 1; span++) {\n const repeat_time = hit_object.time + (span + 1) * span_duration;\n const path_progress = (span + 1) % 2; // 0 or 1 alternating\n\n this.repeats.push({\n pos: this.get_position_at_progress(path_progress),\n time: repeat_time,\n repeat_index: span,\n path_progress\n });\n }\n\n // generate ticks for each span\n for (let span = 0; span < span_count; span++) {\n const span_start_time = hit_object.time + span * span_duration;\n const reversed = span % 2 === 1;\n\n for (let d = tick_distance; d < path_length; d += tick_distance) {\n if (d >= path_length - min_distance_from_end) break;\n\n const path_progress = d / path_length;\n const time_progress = reversed ? 1 - path_progress : path_progress;\n\n this.ticks.push({\n pos: this.get_position_at_progress(path_progress),\n time: span_start_time + time_progress * span_duration,\n span_index: span,\n path_progress\n });\n }\n }\n\n // sort ticks by time for correct rendering\n this.ticks.sort((a, b) => a.time - b.time);\n }\n\n private calculate_path_length(): number {\n let length = 0;\n for (let i = 1; i < this.path.length; i++) {\n length += vec2_len(vec2_sub(this.path[i], this.path[i - 1]));\n }\n return length;\n }\n\n update(time: number): void {\n super.update(time);\n this.calculate_ball_position(time);\n this.calculate_opacities(time);\n }\n\n private calculate_ball_position(time: number): void {\n const { hit_object, span_duration } = this;\n const FOLLOW_IN_DURATION = 300;\n const FOLLOW_OUT_DURATION = 300;\n const FOLLOW_AREA = 2.4;\n\n // before slider starts\n if (time < hit_object.time) {\n this.ball_alpha = 0;\n this.follow_alpha = 0;\n this.follow_scale = 1;\n return;\n }\n\n // during slider\n if (time <= hit_object.end_time) {\n const elapsed = time - hit_object.time;\n const repeat_time = elapsed % (span_duration * 2);\n let t = repeat_time < span_duration ? repeat_time / span_duration : 2 - repeat_time / span_duration;\n t = clamp(t, 0, 1);\n\n this.ball_position = this.get_position_at_progress(t);\n this.ball_alpha = 1;\n\n // follow circle animates in with OutQuint\n const follow_in_progress = clamp(elapsed / FOLLOW_IN_DURATION, 0, 1);\n const eased_in = Easing.OutQuint(follow_in_progress);\n this.follow_alpha = eased_in;\n this.follow_scale = 1 + (FOLLOW_AREA - 1) * eased_in;\n return;\n }\n\n // after slider ends - animate out\n const time_since_end = time - hit_object.end_time;\n const fade_progress = clamp(time_since_end / FOLLOW_OUT_DURATION, 0, 1);\n const eased_out = Easing.OutQuint(fade_progress);\n\n this.ball_alpha = 1 - eased_out;\n this.follow_alpha = 1 - eased_out;\n this.follow_scale = FOLLOW_AREA - (FOLLOW_AREA - 1) * eased_out;\n }\n\n private get_position_at_progress(progress: number): Vec2 {\n const target_length = progress * this.path_length;\n return this.get_position_at_length(target_length);\n }\n\n private get_position_at_length(target_length: number): Vec2 {\n let accumulated = 0;\n for (let i = 1; i < this.path.length; i++) {\n const segment_length = vec2_len(vec2_sub(this.path[i], this.path[i - 1]));\n if (accumulated + segment_length >= target_length) {\n const local_t = (target_length - accumulated) / segment_length;\n return vec2_lerp(this.path[i - 1], this.path[i], local_t);\n }\n accumulated += segment_length;\n }\n return this.path[this.path.length - 1];\n }\n\n private calculate_opacities(time: number): void {\n const { hit_object, config } = this;\n const appear_time = hit_object.time - config.preempt;\n const hit_time = hit_object.time;\n\n // body: fade in over fade_in, then fade out 240ms after end\n if (time < appear_time) {\n this.body_alpha = 0;\n } else if (time < hit_time) {\n this.body_alpha = clamp((time - appear_time) / config.fade_in, 0, 1);\n } else if (time <= hit_object.end_time) {\n this.body_alpha = 1;\n } else {\n this.body_alpha = 1 - clamp((time - hit_object.end_time) / FADE_OUT_DURATION, 0, 1);\n }\n\n // head: same fade in, hit animation at hit_time\n if (time < appear_time) {\n this.head_alpha = 0;\n this.head_scale = 1;\n } else if (time < hit_time) {\n this.head_alpha = clamp((time - appear_time) / config.fade_in, 0, 1);\n this.head_scale = 1;\n } else if (time < hit_time + HEAD_ANIM_DURATION) {\n const progress = (time - hit_time) / HEAD_ANIM_DURATION;\n const eased = Easing.OutCubic(progress);\n this.head_alpha = 1 - eased;\n this.head_scale = 1 + eased * 0.5;\n } else {\n this.head_alpha = 0;\n }\n\n // HD Mod: gradual fade during slider duration, not instant\n if (has_mod(config.mods, Mods.Hidden)) {\n const fade_in_end = hit_time - config.preempt + config.preempt * 0.4;\n const fade_out_start = fade_in_end;\n\n // long fade duration = from fade complete to slider end\n const long_fade_duration = hit_object.end_time - fade_out_start;\n\n if (time > fade_out_start && long_fade_duration > 0) {\n const fade = 1 - clamp((time - fade_out_start) / long_fade_duration, 0, 1);\n this.body_alpha *= fade;\n }\n\n // head fades with standard HD timing\n const head_fade_out_start = hit_time - config.preempt * 0.4;\n const head_fade_out_duration = config.preempt * 0.3;\n\n if (time > head_fade_out_start) {\n const fade = 1 - clamp((time - head_fade_out_start) / head_fade_out_duration, 0, 1);\n this.head_alpha *= fade;\n }\n }\n }\n\n render(time: number): void {\n if (this.body_alpha <= 0 && this.head_alpha <= 0 && this.ball_alpha <= 0) {\n return;\n }\n\n this.render_body(time);\n this.render_head();\n this.render_ball(time);\n }\n\n render_body_pass(time: number): void {\n this.render_body(time);\n }\n\n render_head_pass(time: number): void {\n this.render_head();\n this.render_reverse_arrows(time);\n this.render_ball(time);\n }\n\n private render_body(time: number): void {\n if (this.body_alpha <= 0.01 || this.path.length < 2) return;\n\n const { backend, skin, config, path } = this;\n const { radius } = config;\n\n if (!this.cached_texture) {\n const body_color = get_combo_color(skin, this.combo_number, 1);\n const border_color = skin.slider_border_color ?? \"rgba(255,255,255,1)\";\n const scale = config.scale ?? 1;\n\n this.cached_texture = backend.render_slider_to_image(\n path,\n radius,\n border_color,\n body_color,\n scale,\n skin.slider_body_opacity,\n skin.slider_border_opacity\n );\n }\n\n if (this.cached_texture && this.cached_texture.min_x !== undefined && this.cached_texture.min_y !== undefined) {\n const scale = config.scale ?? 1;\n backend.set_alpha(this.body_alpha);\n backend.draw_image(\n this.cached_texture,\n this.cached_texture.min_x,\n this.cached_texture.min_y,\n this.cached_texture.width / scale,\n this.cached_texture.height / scale\n );\n backend.set_alpha(1);\n }\n\n this.render_ticks(time);\n }\n\n private render_ticks(time: number): void {\n if (this.ticks.length === 0) return;\n\n const { backend, config, hit_object } = this;\n const { radius } = config;\n\n const base_tick_radius = radius * 0.12;\n const appear_time = hit_object.time - config.preempt;\n const snake_progress = clamp((time - appear_time) / config.preempt, 0, 1);\n\n const ANIM_DURATION = 150;\n const SCALE_DURATION = ANIM_DURATION * 4;\n\n for (const tick of this.ticks) {\n // tick already passed\n if (time > tick.time) continue;\n\n // tick not yet visible (snaking)\n if (snake_progress < tick.path_progress) continue;\n\n // calculate when this tick became visible\n const tick_appear_time = appear_time + tick.path_progress * config.preempt;\n const elapsed_since_appear = time - tick_appear_time;\n\n if (elapsed_since_appear < 0) continue;\n\n // fade in over ANIM_DURATION (150ms)\n let tick_alpha = clamp(elapsed_since_appear / ANIM_DURATION, 0, 1);\n tick_alpha *= this.body_alpha;\n\n // scale from 0.5 to 1.0 over SCALE_DURATION with elastic out\n const scale_progress = clamp(elapsed_since_appear / SCALE_DURATION, 0, 1);\n const elastic_value = this.ease_out_elastic_half(scale_progress);\n const tick_scale = 0.5 + 0.5 * elastic_value;\n const tick_radius = base_tick_radius * tick_scale;\n\n if (tick_alpha > 0.01) {\n backend.set_alpha(tick_alpha);\n backend.draw_circle(tick.pos[0], tick.pos[1], tick_radius, \"rgba(255,255,255,0.8)\", \"transparent\", 0);\n }\n }\n\n backend.set_alpha(1);\n }\n\n private ease_out_elastic_half(t: number): number {\n if (t <= 0) return 0;\n if (t >= 1) return 1;\n const p = 0.3;\n return Math.pow(2, -10 * t) * Math.sin(((t - p / 4) * (2 * Math.PI)) / p) + 1;\n }\n\n private render_reverse_arrows(time: number): void {\n if (this.repeats.length === 0) return;\n\n const { backend, config, hit_object, span_duration } = this;\n const { radius } = config;\n const arrow_size = radius * 0.6;\n\n for (const repeat of this.repeats) {\n // the first repeat appears with the slider.\n // subsequent repeats appear exactly 2 * SpanDuration before they are hit.\n let time_preempt = config.preempt;\n if (repeat.repeat_index > 0) {\n time_preempt = span_duration * 2;\n } else {\n // the first repeat appears when the slider appears\n time_preempt += hit_object.time - (hit_object.time - config.preempt);\n }\n\n const appear_time = repeat.time - time_preempt;\n const is_at_end = repeat.repeat_index % 2 === 0;\n\n // dont show if not in range\n if (time < appear_time || time > repeat.time + FADE_OUT_DURATION) continue;\n\n // fade in logic: first repeat fades with slider, others pop in\n let alpha = this.body_alpha * 0.9;\n if (repeat.repeat_index === 0) {\n const fade_in_progress = clamp((time - appear_time) / 150, 0, 1);\n alpha *= Easing.OutQuint(fade_in_progress);\n } else {\n // pop in (TimeFadeIn = 0)\n if (time < appear_time) alpha = 0;\n }\n\n if (time > repeat.time) {\n // fade out after hit\n const anim_duration = Math.min(300, span_duration);\n alpha *= 1 - clamp((time - repeat.time) / anim_duration, 0, 1);\n }\n\n if (alpha <= 0.01) continue;\n\n // calculate arrow direction\n const curve = this.path;\n let aim_rotation_vector: Vec2;\n\n if (is_at_end) {\n // arrow at end pointing back\n const search_start = curve.length - 1;\n aim_rotation_vector = curve[0];\n\n for (let i = search_start; i >= 0; i--) {\n if (Math.abs(curve[i][0] - repeat.pos[0]) > 0.01 || Math.abs(curve[i][1] - repeat.pos[1]) > 0.01) {\n aim_rotation_vector = curve[i];\n break;\n }\n }\n } else {\n // arrow at start pointing forward\n aim_rotation_vector = curve[curve.length - 1];\n\n for (let i = 0; i < curve.length; i++) {\n if (Math.abs(curve[i][0] - repeat.pos[0]) > 0.01 || Math.abs(curve[i][1] - repeat.pos[1]) > 0.01) {\n aim_rotation_vector = curve[i];\n break;\n }\n }\n }\n\n const angle = Math.atan2(aim_rotation_vector[1] - repeat.pos[1], aim_rotation_vector[0] - repeat.pos[0]);\n\n // calculate pulsing scale\n let scale = 1.0;\n if (time < repeat.time) {\n const animation_start = hit_object.time - config.preempt;\n const loop_time = (time - animation_start) % ARROW_TOTAL_CYCLE;\n if (loop_time < ARROW_MOVE_OUT_DURATION) {\n scale = 1 + (ARROW_SCALE_AMOUNT - 1) * Easing.Out(loop_time / ARROW_MOVE_OUT_DURATION);\n } else {\n const in_progress = (loop_time - ARROW_MOVE_OUT_DURATION) / ARROW_MOVE_IN_DURATION;\n scale = ARROW_SCALE_AMOUNT - (ARROW_SCALE_AMOUNT - 1) * Easing.Out(clamp(in_progress, 0, 1));\n }\n } else {\n // after hit: scale up\n const anim_duration = Math.min(300, span_duration);\n const progress = clamp((time - repeat.time) / anim_duration, 0, 1);\n scale = 1 + 0.5 * Easing.Out(progress);\n }\n\n const scaled_arrow_size = arrow_size * scale;\n\n backend.save();\n backend.set_alpha(alpha);\n backend.translate(repeat.pos[0], repeat.pos[1]);\n backend.rotate(angle);\n\n backend.begin_path();\n backend.move_to(scaled_arrow_size * 0.8, 0);\n backend.line_to(-scaled_arrow_size * 0.4, -scaled_arrow_size * 0.5);\n backend.line_to(-scaled_arrow_size * 0.4, scaled_arrow_size * 0.5);\n backend.close_path();\n backend.fill_path(\"rgba(255,255,255,0.9)\");\n\n backend.restore();\n }\n }\n\n private render_head(): void {\n if (this.head_alpha <= 0.01) return;\n\n const { backend, skin, config } = this;\n const { radius } = config;\n const pos = this.slider_data.pos;\n const combo_color = get_combo_color(skin, this.combo_number, 1);\n\n const inner_radius = radius * (1 - skin.circle_border_width / 2) * this.head_scale;\n const border_width = radius * skin.circle_border_width * this.head_scale;\n\n backend.set_alpha(this.head_alpha * skin.hit_circle_opacity);\n backend.draw_circle(pos[0], pos[1], inner_radius, combo_color, \"rgba(255,255,255,1)\", border_width);\n\n const font_size = radius * 0.8 * this.head_scale;\n backend.draw_text(\n String(this.combo_count),\n pos[0],\n pos[1] + font_size * 0.05,\n `600 ${font_size}px ${skin.font_family}`,\n \"rgba(255,255,255,1)\",\n \"center\",\n \"middle\"\n );\n\n backend.set_alpha(1);\n }\n\n private render_ball(time: number): void {\n if (this.ball_alpha <= 0.01 && this.follow_alpha <= 0.01) return;\n\n const { backend, skin, config } = this;\n const { radius } = config;\n const pos = this.ball_position;\n const combo_color = get_combo_color(skin, this.combo_number, 0.9);\n\n // follow circle with smooth scale animation\n if (this.follow_alpha > 0.01) {\n const follow_size = radius * this.follow_scale;\n\n backend.set_alpha(this.follow_alpha * skin.follow_circle_opacity);\n backend.begin_path();\n backend.arc_to(pos[0], pos[1], follow_size, 0, Math.PI * 2);\n backend.stroke_path(skin.follow_circle_color, skin.follow_circle_width);\n }\n\n // slider ball\n if (skin.enable_slider_ball && this.ball_alpha > 0.01) {\n backend.set_alpha(this.ball_alpha * skin.slider_ball_opacity);\n backend.draw_circle(pos[0], pos[1], radius * 0.85, combo_color, \"rgba(255,255,255,0.9)\", radius * 0.1);\n }\n\n backend.set_alpha(1);\n }\n}\n",
|
|
27
|
+
"import type { IBeatmap, IHitObject, ISliderData, ITimingPoint } from \"../../types/beatmap\";\nimport { is_circle, is_slider, is_spinner, is_new_combo } from \"../../types/beatmap\";\nimport { Mods, has_mod } from \"../../types/mods\";\nimport { calculate_preempt, calculate_fade_in, calculate_radius } from \"../../math/difficulty\";\nimport { get_adjusted_difficulty } from \"../../mods\";\nimport { flatten_bezier, flatten_linear, flatten_perfect, flatten_catmull } from \"../../math/curves\";\nimport { vec2_sub, vec2_len, vec2_lerp, lerp, clamp, type Vec2 } from \"../../math/vector2\";\nimport { BaseRenderer, type IRendererConfig, DEFAULT_RENDERER_CONFIG } from \"../base_renderer\";\nimport type { IRenderBackend } from \"../backend/render_backend\";\nimport type { ISkinConfig } from \"../../skin/skin_config\";\nimport { get_combo_color } from \"../../skin/skin_config\";\nimport { Drawable, DrawableHitCircle, DrawableSlider, type DrawableConfig } from \"../drawable\";\n\nconst flip_y = (y: number): number => 384 - y;\nconst ease_out_cubic = (t: number): number => 1 - Math.pow(1 - t, 3);\n\nexport class StandardRenderer extends BaseRenderer {\n private radius = 32;\n private preempt = 1200;\n private fade_in = 600;\n private timing_points: ITimingPoint[] = [];\n\n private drawables: Drawable[] = [];\n private drawable_config!: DrawableConfig;\n\n constructor(backend: IRenderBackend, skin: ISkinConfig, mods: number = 0, config: IRendererConfig = DEFAULT_RENDERER_CONFIG) {\n super(backend, skin, mods, config);\n }\n\n initialize(beatmap: IBeatmap): void {\n this.beatmap = beatmap;\n this.objects = JSON.parse(JSON.stringify(beatmap.objects)).sort((a: IHitObject, b: IHitObject) => a.time - b.time);\n this.timing_points = this.process_timing_points([...beatmap.timing_points]);\n\n const difficulty = get_adjusted_difficulty(beatmap.cs, beatmap.ar, 0, 0, this.mods);\n this.radius = calculate_radius(difficulty.cs);\n this.preempt = calculate_preempt(difficulty.ar);\n this.fade_in = calculate_fade_in(this.preempt);\n\n this.preprocess_objects();\n this.create_drawables();\n }\n\n set_mods(mods: number): void {\n this.mods = mods;\n if (this.beatmap) {\n this.initialize(this.beatmap);\n }\n }\n\n private process_timing_points(points: ITimingPoint[]): ITimingPoint[] {\n if (points.length === 0) {\n return points;\n }\n\n points[0].time = 0;\n let base_ms_per_beat = points[0].ms_per_beat;\n\n for (const point of points) {\n if (point.ms_per_beat < 0) {\n point.ms_per_beat = base_ms_per_beat * (-point.ms_per_beat / 100);\n } else {\n base_ms_per_beat = point.ms_per_beat;\n }\n }\n\n return points.reverse();\n }\n\n private preprocess_objects(): void {\n let combo_number = 0;\n let combo_count = 1;\n\n for (const obj of this.objects) {\n if (is_new_combo(obj)) {\n combo_number = (combo_number + 1) % this.skin.combo_colors.length;\n combo_count = 1;\n } else {\n combo_count++;\n }\n obj.combo_number = combo_number;\n obj.combo_count = combo_count;\n\n if (is_slider(obj)) {\n const data = obj.data as ISliderData;\n\n if (has_mod(this.mods, Mods.HardRock)) {\n data.pos = [data.pos[0], flip_y(data.pos[1])];\n data.control_points = data.control_points.map((p) => [p[0], flip_y(p[1])] as [number, number]);\n }\n\n data.computed_path = this.compute_slider_path(data);\n\n const timing = this.get_timing_at(obj.time);\n const duration = (data.distance / (100 * this.beatmap!.sv)) * timing.ms_per_beat;\n\n data.duration = duration;\n obj.end_time = obj.time + duration * data.repetitions;\n obj.end_pos = this.get_slider_end_position(data);\n } else if (is_spinner(obj)) {\n obj.end_pos = [256, 192];\n } else {\n const data = obj.data as { pos: Vec2 };\n if (has_mod(this.mods, Mods.HardRock)) {\n data.pos = [data.pos[0], flip_y(data.pos[1])];\n }\n obj.end_pos = data.pos;\n }\n }\n }\n\n private create_drawables(): void {\n this.drawables = [];\n const dpr = this.config.use_high_dpi ? window.devicePixelRatio || 1 : 1;\n this.drawable_config = {\n backend: this.backend,\n skin: this.skin,\n preempt: this.preempt,\n fade_in: this.fade_in,\n radius: this.radius,\n scale: this.config.scale * dpr,\n mods: this.mods\n };\n\n for (const obj of this.objects) {\n if (is_circle(obj)) {\n this.drawables.push(new DrawableHitCircle(obj, this.drawable_config));\n } else if (is_slider(obj)) {\n const data = obj.data as ISliderData;\n const path = data.computed_path || [];\n const span_duration = data.duration || 0;\n\n // velocity = path_distance / span_duration\n // scoring_distance = velocity * beat_length\n // tick_distance = scoring_distance / tick_rate\n const path_length = this.calculate_path_length(path);\n const velocity = span_duration > 0 ? path_length / span_duration : 0;\n const base_beat_length = this.get_base_beat_length_at(obj.time);\n const scoring_distance = velocity * base_beat_length;\n const tick_distance = scoring_distance / this.beatmap!.tick_rate;\n\n this.drawables.push(new DrawableSlider(obj, this.drawable_config, path, span_duration, tick_distance));\n }\n }\n }\n\n private calculate_path_length(path: Vec2[]): number {\n let length = 0;\n for (let i = 1; i < path.length; i++) {\n length += vec2_len(vec2_sub(path[i], path[i - 1]));\n }\n return length;\n }\n\n private get_base_beat_length_at(time: number): number {\n if (!this.beatmap || this.beatmap.timing_points.length === 0) return 600;\n\n let last_valid = this.beatmap.timing_points[0].ms_per_beat;\n\n for (const p of this.beatmap.timing_points) {\n if (p.time > time) break;\n if (p.change) {\n // uninherited\n last_valid = p.ms_per_beat;\n }\n }\n return last_valid;\n }\n\n render(time: number): void {\n const { backend, config } = this;\n\n this.render_background();\n backend.save();\n backend.translate(config.offset_x, config.offset_y);\n backend.scale(config.scale, config.scale);\n this.render_playfield();\n this.render_grid();\n\n // get visible drawables\n const visible_drawables = this.drawables.filter((d) => d.is_alive(time));\n\n // draw follow points\n this.draw_follow_points(time);\n\n // draw spinners first (background layer)\n for (const obj of this.objects) {\n if (is_spinner(obj)) {\n const appear_time = obj.time - this.preempt;\n if (time >= appear_time && time <= obj.end_time + 200) {\n this.draw_spinner(obj, time);\n }\n }\n }\n\n // update and render drawables in reverse order (later objects at back)\n // using 2-pass rendering: bodies first, then heads/circles on top\n visible_drawables.sort((a, b) => b.start_time - a.start_time);\n\n for (const drawable of visible_drawables) {\n drawable.update(time);\n }\n\n // pass 1: bodies only (sliders)\n for (const drawable of visible_drawables) {\n if (drawable instanceof DrawableSlider) {\n drawable.render_body_pass(time);\n }\n }\n\n // pass 2: circles/heads on top\n for (const drawable of visible_drawables) {\n if (drawable instanceof DrawableSlider) {\n drawable.render_head_pass(time);\n } else {\n drawable.render(time);\n }\n }\n\n // approach circles (on top of everything except cursor)\n if (!has_mod(this.mods, Mods.Hidden) && this.skin.enable_approach_circle) {\n for (const drawable of visible_drawables) {\n if (time <= drawable.start_time) {\n this.draw_approach_circle(drawable, time);\n }\n }\n }\n\n backend.restore();\n }\n\n private draw_follow_points(time: number): void {\n if (has_mod(this.mods, Mods.Hidden)) return;\n\n for (let i = 0; i < this.objects.length - 1; i++) {\n const prev = this.objects[i];\n const next = this.objects[i + 1];\n\n if (is_spinner(prev) || is_spinner(next)) continue;\n if (prev.combo_number !== next.combo_number) continue;\n if (time < prev.end_time || time > next.time) continue;\n\n const start_pos = prev.end_pos;\n const end_pos = (next.data as { pos: Vec2 }).pos;\n\n const dx = end_pos[0] - start_pos[0];\n const dy = end_pos[1] - start_pos[1];\n const distance = Math.sqrt(dx * dx + dy * dy);\n if (distance < 48) continue;\n\n const duration = next.time - prev.end_time;\n const progress = (time - prev.end_time) / duration;\n let opacity = 1.0;\n\n if (progress < 0.2) opacity = progress / 0.2;\n if (progress > 0.8) opacity = (1 - progress) / 0.2;\n if (opacity <= 0) continue;\n\n const line_progress = clamp(progress * 1.5, 0, 1);\n const line_start_x = lerp(start_pos[0], end_pos[0], Math.max(0, progress - 0.3));\n const line_start_y = lerp(start_pos[1], end_pos[1], Math.max(0, progress - 0.3));\n const line_end_x = lerp(start_pos[0], end_pos[0], line_progress);\n const line_end_y = lerp(start_pos[1], end_pos[1], line_progress);\n\n this.backend.set_alpha(opacity * 0.6);\n this.backend.begin_path();\n this.backend.move_to(line_start_x, line_start_y);\n this.backend.line_to(line_end_x, line_end_y);\n this.backend.stroke_path(\"rgba(255,255,255,1)\", this.skin.follow_point_width, \"round\", \"round\");\n this.backend.set_alpha(1);\n }\n }\n\n private draw_approach_circle(drawable: Drawable, time: number): void {\n const pos = drawable.position;\n const appear_time = drawable.start_time - this.preempt;\n\n // fade in with OutQuint for smoother animation\n const fade_duration = Math.min(this.fade_in * 2, this.preempt);\n const fade_progress = clamp((time - appear_time) / fade_duration, 0, 1);\n const opacity = this.ease_out_quint(fade_progress) * this.skin.approach_circle_opacity;\n\n // scale from 4 to 1 linearly over preempt time\n const scale_progress = clamp((time - appear_time) / this.preempt, 0, 1);\n const scale = 4 - 3 * scale_progress;\n\n const combo_color = get_combo_color(this.skin, drawable.combo_number, 1);\n\n this.backend.save();\n this.backend.set_alpha(opacity);\n this.backend.draw_circle(pos[0], pos[1], this.radius * scale, \"transparent\", combo_color, this.radius * this.skin.approach_circle_width);\n this.backend.restore();\n }\n\n private ease_out_quint(t: number): number {\n return 1 - Math.pow(1 - t, 5);\n }\n\n private draw_spinner(obj: IHitObject, time: number): void {\n const appear_time = obj.time - this.preempt;\n let opacity = clamp((time - appear_time) / this.fade_in, 0, 1);\n\n if (time > obj.end_time) {\n opacity = 1 - ease_out_cubic(clamp((time - obj.end_time) / 200, 0, 1));\n }\n if (opacity <= 0) return;\n\n const x = 256,\n y = 192;\n const duration = obj.end_time - obj.time;\n const progress = clamp((time - obj.time) / duration, 0, 1);\n\n this.backend.set_alpha(opacity);\n const approach_size = this.skin.spinner_size * (1 - progress);\n\n if (approach_size > 5) {\n this.backend.begin_path();\n this.backend.arc_to(x, y, approach_size, 0, Math.PI * 2);\n this.backend.stroke_path(\"rgba(255,255,255,0.6)\", 4);\n }\n\n this.backend.draw_circle(x, y, this.skin.spinner_size, \"rgba(0,0,0,0.2)\");\n this.backend.draw_circle(x, y, 12, \"white\");\n }\n\n private compute_slider_path(slider: ISliderData): Vec2[] {\n if (slider.path_type === \"L\") {\n return flatten_linear(slider.pos, slider.control_points[0], slider.distance);\n }\n\n const all_points: Vec2[] = [slider.pos, ...slider.control_points];\n\n switch (slider.path_type) {\n case \"P\":\n return flatten_perfect(all_points, slider.distance);\n case \"C\":\n return flatten_catmull(all_points);\n default:\n return this.flatten_multibezier(all_points, slider.distance);\n }\n }\n\n private flatten_multibezier(points: Vec2[], max_distance: number): Vec2[] {\n const segments: Vec2[][] = [];\n let current: Vec2[] = [points[0]];\n\n for (let i = 1; i < points.length; i++) {\n const [prev, cur] = [points[i - 1], points[i]];\n\n if (prev[0] === cur[0] && prev[1] === cur[1]) {\n if (current.length > 1) segments.push(current);\n current = [cur];\n } else {\n current.push(cur);\n }\n }\n\n if (current.length > 1) segments.push(current);\n\n const all_points: Vec2[] = [];\n\n for (const segment of segments) {\n all_points.push(...flatten_bezier(segment));\n }\n\n return this.clamp_path_to_distance(all_points, max_distance);\n }\n\n private clamp_path_to_distance(path: Vec2[], max_distance: number): Vec2[] {\n if (path.length < 2) return path;\n const result: Vec2[] = [path[0]];\n let distance = 0;\n\n for (let i = 1; i < path.length; i++) {\n const segment_length = vec2_len(vec2_sub(path[i], path[i - 1]));\n if (distance + segment_length >= max_distance) {\n const remaining = max_distance - distance;\n result.push(vec2_lerp(path[i - 1], path[i], remaining / segment_length));\n break;\n }\n distance += segment_length;\n result.push(path[i]);\n }\n return result;\n }\n\n private get_timing_at(time: number): ITimingPoint {\n for (const point of this.timing_points) {\n if (point.time <= time) return point;\n }\n return this.timing_points[this.timing_points.length - 1];\n }\n\n private get_slider_end_position(slider: ISliderData): Vec2 {\n if (!slider.computed_path || slider.computed_path.length === 0) return slider.pos;\n return slider.repetitions % 2 === 0 ? slider.pos : slider.computed_path[slider.computed_path.length - 1];\n }\n}\n",
|
|
28
|
+
"import type { IBeatmap, IHitObject, IHoldData } from \"../../types/beatmap\";\nimport { is_hold } from \"../../types/beatmap\";\nimport { Mods, has_mod } from \"../../types/mods\";\nimport { get_rate_multiplier } from \"../../mods\";\nimport { BaseRenderer, type IRendererConfig, DEFAULT_RENDERER_CONFIG, PLAYFIELD_WIDTH, PLAYFIELD_HEIGHT } from \"../base_renderer\";\nimport type { IRenderBackend } from \"../backend/render_backend\";\nimport type { ISkinConfig } from \"../../skin/skin_config\";\nimport { get_mania_lane_color } from \"../../skin/skin_config\";\n\nconst MAX_TIME_RANGE = 11485;\nconst BASE_SCROLL_SPEED = 20;\n\nexport class ManiaRenderer extends BaseRenderer {\n private key_count: number = 4;\n private scroll_time: number = MAX_TIME_RANGE / BASE_SCROLL_SPEED;\n\n // overlay constants (configurable)\n private hd_coverage: number = 0.25; // bottom 25% for hidden\n private fi_coverage: number = 0.6; // top 60% for fade-in\n private gradient_ratio: number = 0.2; // fade region is 20% of playfield height\n\n constructor(backend: IRenderBackend, skin: ISkinConfig, mods: number = 0, config: IRendererConfig = DEFAULT_RENDERER_CONFIG) {\n super(backend, skin, mods, config);\n this.update_scroll_time();\n }\n\n initialize(beatmap: IBeatmap): void {\n this.beatmap = beatmap;\n this.objects = [...beatmap.objects];\n this.key_count = Math.floor(beatmap.cs);\n\n for (const obj of this.objects) {\n if (is_hold(obj)) {\n obj.end_time = (obj.data as IHoldData).end_time;\n }\n }\n }\n\n set_mods(mods: number): void {\n this.mods = mods;\n this.update_scroll_time();\n }\n\n private update_scroll_time(): void {\n const rate = get_rate_multiplier(this.mods);\n this.scroll_time = MAX_TIME_RANGE / (BASE_SCROLL_SPEED * rate);\n }\n\n private time_to_y(time_diff: number): number {\n const hit_pos = this.skin.mania_hit_position;\n const progress = time_diff / this.scroll_time;\n return hit_pos - progress * hit_pos;\n }\n\n render(time: number): void {\n const { backend, config, skin, key_count } = this;\n\n this.render_background();\n\n const total_width = key_count * skin.mania_lane_width;\n const x_offset = Math.floor((PLAYFIELD_WIDTH - total_width) / 2);\n const hit_pos = skin.mania_hit_position;\n\n backend.save();\n backend.translate(config.offset_x, config.offset_y);\n backend.scale(config.scale, config.scale);\n\n this.render_playfield(total_width, PLAYFIELD_HEIGHT, x_offset);\n\n // draw lane keys at judgment line\n this.draw_lane_keys(time, x_offset);\n this.draw_judgment_line(x_offset);\n\n // clip notes to playfield above judgment line\n backend.save();\n backend.begin_path();\n backend.rect(x_offset, 0, total_width, hit_pos);\n backend.clip();\n\n // dim background for lanes\n backend.set_alpha(0.7);\n backend.draw_rect(x_offset, 0, total_width, hit_pos, \"#000000\");\n backend.set_alpha(1);\n\n // draw visible objects (those that haven't ended yet)\n for (const obj of this.objects) {\n if (obj.end_time < time) {\n continue;\n }\n\n if (is_hold(obj)) {\n this.draw_hold_note(obj, time, x_offset);\n } else {\n this.draw_note(obj, time, x_offset);\n }\n }\n\n // draw cover overlay for hd/fadein\n if (has_mod(this.mods, Mods.Hidden) || has_mod(this.mods, Mods.FadeIn)) {\n const coverage_ratio = has_mod(this.mods, Mods.Hidden) ? this.hd_coverage : this.fi_coverage;\n const total_h = hit_pos * coverage_ratio;\n const grad_h = hit_pos * this.gradient_ratio;\n\n if (has_mod(this.mods, Mods.Hidden)) {\n const start_y = hit_pos - total_h;\n const fade_end = grad_h / total_h;\n\n const gradient = backend.create_linear_gradient(x_offset, start_y, x_offset, hit_pos, [\n { offset: 0.0, color: \"rgba(0,0,0,0)\" },\n { offset: fade_end * 0.4, color: \"rgba(0,0,0,0.3)\" },\n { offset: fade_end * 0.7, color: \"rgba(0,0,0,0.75)\" },\n { offset: fade_end * 0.9, color: \"rgba(0,0,0,0.95)\" },\n { offset: fade_end, color: \"rgba(0,0,0,1)\" },\n { offset: 1.0, color: \"rgba(0,0,0,1)\" }\n ]);\n backend.draw_rect_gradient(x_offset, start_y, total_width, total_h, gradient);\n } else {\n const fade_start = (total_h - grad_h) / total_h;\n const gradient = backend.create_linear_gradient(x_offset, 0, x_offset, total_h, [\n { offset: 0.0, color: \"rgba(0,0,0,1)\" },\n { offset: fade_start, color: \"rgba(0,0,0,1)\" },\n { offset: fade_start + (1 - fade_start) * 0.1, color: \"rgba(0,0,0,0.95)\" },\n { offset: fade_start + (1 - fade_start) * 0.4, color: \"rgba(0,0,0,0.75)\" },\n { offset: fade_start + (1 - fade_start) * 0.7, color: \"rgba(0,0,0,0.3)\" },\n { offset: 1.0, color: \"rgba(0,0,0,0)\" }\n ]);\n backend.draw_rect_gradient(x_offset, 0, total_width, total_h, gradient);\n }\n }\n backend.restore();\n backend.restore();\n }\n\n private get_lane(obj: IHitObject): number {\n const pos = (obj.data as { pos: [number, number] }).pos;\n let lane = Math.floor((pos[0] * this.key_count) / 512);\n\n if (has_mod(this.mods, Mods.Mirror)) {\n lane = this.key_count - 1 - lane;\n }\n\n return lane;\n }\n\n private draw_note(obj: IHitObject, time: number, x_offset: number): void {\n const { backend, skin, key_count } = this;\n const lane = this.get_lane(obj);\n\n const lane_width = skin.mania_lane_width;\n const note_height = skin.mania_note_height;\n const spacing = skin.mania_lane_spacing;\n\n // calculate Y position from time difference\n const time_diff = obj.time - time;\n const y = this.time_to_y(time_diff);\n\n // skip if note is too far above screen\n if (y < -note_height - 64) {\n return;\n }\n\n const x = x_offset + lane * lane_width;\n const color = get_mania_lane_color(skin, key_count, lane);\n\n backend.set_alpha(1.0);\n backend.draw_rect(x + spacing, y - note_height, lane_width - 2 * spacing, note_height, color);\n }\n\n private draw_hold_note(obj: IHitObject, time: number, x_offset: number): void {\n const { backend, skin, key_count } = this;\n const data = obj.data as IHoldData;\n const lane = this.get_lane(obj);\n\n const lane_width = skin.mania_lane_width;\n const note_height = skin.mania_note_height;\n const spacing = skin.mania_lane_spacing;\n\n // calculate head and tail Y positions\n const head_time_diff = obj.time - time;\n const tail_time_diff = data.end_time - time;\n\n const head_y = this.time_to_y(head_time_diff);\n const tail_y = this.time_to_y(tail_time_diff);\n\n const x = x_offset + lane * lane_width;\n const color = get_mania_lane_color(skin, key_count, lane);\n\n // skip if entirely off screen\n if (tail_y < -64 && head_y < -64) {\n return;\n }\n\n // draw body (from tail to judgment line or head, whichever is lower)\n const body_top = tail_y;\n const body_bottom = head_time_diff < 0 ? skin.mania_hit_position : head_y;\n const body_height = body_bottom - body_top;\n\n if (body_height > 0) {\n backend.set_alpha(0.9);\n backend.draw_rect(x + spacing, body_top, lane_width - 2 * spacing, body_height, color);\n }\n\n // only draw head if not yet hit (before hit time)\n if (head_time_diff >= 0) {\n backend.set_alpha(1.0);\n backend.draw_rect(x + spacing, head_y - note_height, lane_width - 2 * spacing, note_height, color);\n }\n\n backend.set_alpha(1); // reset after hold note\n }\n\n private draw_judgment_line(x_offset: number): void {\n const { backend, skin, key_count } = this;\n const lane_width = skin.mania_lane_width;\n const hit_pos = skin.mania_hit_position;\n\n backend.draw_rect(x_offset, hit_pos - 1, lane_width * key_count, 2, \"#ffffff\");\n }\n\n private draw_lane_keys(time: number, x_offset: number): void {\n const { backend, skin, key_count } = this;\n const { mania_lane_width: lane_width, mania_hit_position: hit_pos, mania_lane_spacing: spacing, mania_note_height: note_height } = skin;\n const key_height = note_height + 5;\n\n const pressed = new Set<number>();\n const HIT_WINDOW = 50;\n\n for (const obj of this.objects) {\n if (time >= obj.time - HIT_WINDOW && time <= obj.end_time + HIT_WINDOW) {\n pressed.add(this.get_lane(obj));\n }\n }\n\n for (let i = 0; i < key_count; i++) {\n const is_pressed = pressed.has(i);\n const x = x_offset + i * lane_width;\n const color = get_mania_lane_color(skin, key_count, i);\n\n backend.set_alpha(0.3);\n backend.draw_rect(x + spacing, hit_pos, lane_width - 2 * spacing, key_height, color);\n\n if (is_pressed) {\n backend.set_alpha(1.0);\n backend.draw_rect(x + spacing, hit_pos, lane_width - 2 * spacing, key_height, \"#ff6666\");\n }\n }\n\n backend.set_alpha(1);\n }\n}\n",
|
|
29
|
+
"import { get_speed_multiplier } from \"../types/mods\";\n\nexport class AudioController {\n private audio_context: AudioContext;\n private audio_source: AudioBufferSourceNode | null = null;\n private audio_buffer: AudioBuffer | null = null;\n private gain_node: GainNode;\n\n private start_time: number = 0;\n private pause_time: number = 0;\n private speed: number = 1;\n private _is_playing: boolean = false;\n private _duration: number = 0;\n private _is_loaded: boolean = false;\n\n constructor(context: AudioContext) {\n this.audio_context = context;\n this.gain_node = this.audio_context.createGain();\n this.gain_node.connect(this.audio_context.destination);\n }\n\n get is_playing(): boolean {\n return this._is_playing;\n }\n get is_loaded(): boolean {\n return this._is_loaded;\n }\n get duration(): number {\n return this._duration;\n }\n get speed_multiplier(): number {\n return this.speed;\n }\n\n get current_time(): number {\n if (!this._is_playing) {\n return this.pause_time;\n }\n return (this.audio_context.currentTime - this.start_time) * this.speed * 1000;\n }\n\n async load(data: ArrayBuffer, mods: number = 0): Promise<void> {\n this.stop();\n\n try {\n // copy buffer to avoid issues if source is detached\n this.audio_buffer = await this.audio_context.decodeAudioData(data.slice(0));\n this._duration = this.audio_buffer.duration * 1000;\n this.speed = get_speed_multiplier(mods);\n this._is_loaded = true;\n this.pause_time = 0;\n } catch (e) {\n console.error(\"Failed to decode audio data\", e);\n throw e;\n }\n }\n\n play(from_time?: number): void {\n if (!this.audio_buffer) {\n console.warn(\"[AudioController] Cannot play: not loaded\");\n return;\n }\n\n // stop current source if exists\n this.stop_source();\n\n const start_offset = from_time !== undefined ? from_time / 1000 : this.pause_time / 1000;\n\n // clamp to valid range\n const duration = this.audio_buffer.duration;\n const clamped_offset = Math.max(0, Math.min(start_offset, duration));\n\n if (clamped_offset >= duration) {\n // seeking past end\n this.pause_time = duration * 1000;\n return;\n }\n\n this.audio_source = this.audio_context.createBufferSource();\n this.audio_source.buffer = this.audio_buffer;\n this.audio_source.playbackRate.value = this.speed;\n this.audio_source.connect(this.gain_node);\n\n this.audio_source.onended = () => {\n if (this._is_playing) {\n this._is_playing = false;\n this.pause_time = this._duration;\n this.audio_source = null;\n }\n };\n\n this.start_time = this.audio_context.currentTime - clamped_offset / this.speed;\n this.audio_source.start(0, clamped_offset);\n this._is_playing = true;\n }\n\n pause(): void {\n if (!this._is_playing) return;\n\n // save current position before stopping\n this.pause_time = this.current_time;\n this.stop_source();\n this._is_playing = false;\n }\n\n seek(time_ms: number): void {\n const clamped = Math.max(0, Math.min(time_ms, this._duration));\n\n if (this._is_playing) {\n // stop and restart at new position\n this.stop_source();\n this._is_playing = false;\n this.pause_time = clamped;\n this.play();\n } else {\n this.pause_time = clamped;\n }\n }\n\n stop(): void {\n this.pause();\n this.pause_time = 0;\n }\n\n get_host_time(time_ms: number): number {\n // returns the AudioContext time corresponding to the given map time\n // current_time = (ctx_time - start_time) * speed * 1000\n // ctx_time = (current_time / 1000 / speed) + start_time\n return this.start_time + time_ms / 1000 / this.speed;\n }\n\n private stop_source(): void {\n if (this.audio_source) {\n try {\n this.audio_source.onended = null;\n this.audio_source.stop();\n this.audio_source.disconnect();\n } catch {\n // ignore errors\n }\n this.audio_source = null;\n }\n }\n\n set_volume(volume: number): void {\n if (this.gain_node) {\n this.gain_node.gain.value = Math.max(0, Math.min(1, volume));\n }\n }\n\n set_speed(speed: number): void {\n if (this._is_playing) {\n // capture current position before speed change\n const current_pos = this.current_time;\n this.speed = speed;\n // recalculate start_time for new speed\n this.start_time = this.audio_context.currentTime - current_pos / 1000 / speed;\n } else {\n this.speed = speed;\n }\n\n if (this.audio_source) {\n this.audio_source.playbackRate.value = speed;\n }\n }\n\n dispose(): void {\n this.stop();\n this.audio_buffer = null;\n this._is_loaded = false;\n\n // disconnect gain node but don't close context (shared)\n this.gain_node.disconnect();\n }\n}\n",
|
|
25
30
|
"export class VideoController {\n private video: HTMLVideoElement | null = null;\n private object_url: string | null = null;\n private _offset: number = 0;\n private speed: number = 1;\n\n get element(): HTMLVideoElement | null {\n return this.video;\n }\n\n get offset(): number {\n return this._offset;\n }\n\n async load(data: Blob, offset: number = 0, speed: number = 1): Promise<void> {\n this.dispose();\n\n this._offset = offset;\n this.speed = speed;\n\n this.video = document.createElement(\"video\");\n this.video.muted = true;\n this.video.loop = false;\n this.video.playsInline = true;\n\n this.object_url = URL.createObjectURL(data);\n this.video.src = this.object_url;\n\n await new Promise<void>((resolve, reject) => {\n if (!this.video) return reject(new Error(\"No video element\"));\n this.video.onloadeddata = () => resolve();\n this.video.onerror = () => reject(new Error(\"Failed to load video\"));\n });\n\n this.video.playbackRate = speed;\n }\n\n sync(audio_time_ms: number): void {\n if (!this.video) return;\n\n const video_time = (audio_time_ms - this._offset) / 1000;\n\n // only sync if visible (after offset)\n if (video_time < 0) {\n if (!this.video.paused) {\n this.video.pause();\n }\n return;\n }\n\n // check if video is out of sync\n const diff = Math.abs(this.video.currentTime - video_time);\n\n if (diff > 0.1) {\n this.video.currentTime = video_time;\n }\n }\n\n play(): void {\n if (this.video && this.video.paused) {\n this.video.play().catch(() => {\n console.log(\"failed to play video\");\n });\n }\n }\n\n pause(): void {\n if (this.video && !this.video.paused) {\n this.video.pause();\n }\n }\n\n seek(time_ms: number): void {\n if (!this.video) return;\n\n const video_time = Math.max(0, (time_ms - this._offset) / 1000);\n this.video.currentTime = video_time;\n }\n\n set_speed(speed: number): void {\n this.speed = speed;\n if (this.video) {\n this.video.playbackRate = speed;\n }\n }\n\n dispose(): void {\n if (this.video) {\n this.video.pause();\n this.video.src = \"\";\n this.video = null;\n }\n\n if (this.object_url) {\n URL.revokeObjectURL(this.object_url);\n this.object_url = null;\n }\n }\n}\n",
|
|
26
31
|
"import { SampleSet, HitSoundType } from \"../types/beatmap\";\n\nexport class HitsoundController {\n private context: AudioContext;\n private gain_node: GainNode;\n private samples: Map<string, AudioBuffer> = new Map();\n private volume: number = 1;\n\n constructor(context: AudioContext) {\n this.context = context;\n this.gain_node = context.createGain();\n this.gain_node.connect(context.destination);\n }\n\n set_volume(volume: number): void {\n this.volume = Math.max(0, Math.min(1, volume));\n this.gain_node.gain.value = this.volume;\n }\n\n async load_samples(files: Map<string, ArrayBuffer>): Promise<void> {\n this.samples.clear();\n\n const decode_promises: Promise<void>[] = [];\n\n for (const [name, buffer] of files) {\n if (name.endsWith(\".wav\") || name.endsWith(\".mp3\") || name.endsWith(\".ogg\")) {\n decode_promises.push(\n this.context\n .decodeAudioData(buffer.slice(0))\n .then((audio_buffer) => {\n const key = name.toLowerCase().replace(/\\.(wav|mp3|ogg)$/, \"\");\n this.samples.set(key, audio_buffer);\n })\n .catch((err) => {\n console.warn(`[HitsoundController] Failed to decode ${name}:`, err);\n })\n );\n }\n }\n\n await Promise.all(decode_promises);\n }\n\n play(\n normal_set: SampleSet,\n addition_set: SampleSet,\n hit_sound: number,\n index: number,\n volume: number = 100,\n custom_filename?: string,\n when: number = 0\n ): void {\n const normal_name = this.get_set_name(normal_set);\n const addition_name = this.get_set_name(addition_set);\n\n if (custom_filename) {\n const key = custom_filename.toLowerCase().replace(/\\.(wav|mp3|ogg)$/, \"\");\n if (this.play_buffer(key, volume, when)) return;\n }\n\n this.play_sound(normal_name, \"hitnormal\", index, volume, when);\n\n if (hit_sound & HitSoundType.Whistle) {\n this.play_sound(addition_name, \"hitwhistle\", index, volume, when);\n }\n if (hit_sound & HitSoundType.Finish) {\n this.play_sound(addition_name, \"hitfinish\", index, volume, when);\n }\n if (hit_sound & HitSoundType.Clap) {\n this.play_sound(addition_name, \"hitclap\", index, volume, when);\n }\n }\n\n private play_sound(set: string, type: string, index: number, volume: number, when: number): void {\n let played = false;\n\n if (index > 1) {\n played = this.play_buffer(`${set}-${type}${index}`, volume, when);\n }\n\n if (!played) {\n this.play_buffer(`${set}-${type}`, volume, when);\n }\n }\n\n private play_buffer(key: string, volume: number, when: number): boolean {\n const buffer = this.samples.get(key);\n if (!buffer) return false;\n\n const source = this.context.createBufferSource();\n source.buffer = buffer;\n\n const gain = this.context.createGain();\n gain.gain.value = volume / 100;\n\n source.connect(gain);\n gain.connect(this.gain_node);\n\n source.start(when);\n return true;\n }\n\n private get_set_name(set: SampleSet): string {\n switch (set) {\n case SampleSet.Drum:\n return \"drum\";\n case SampleSet.Soft:\n return \"soft\";\n default:\n return \"normal\";\n }\n }\n\n dispose(): void {\n this.samples.clear();\n this.gain_node.disconnect();\n }\n}\n",
|
|
27
|
-
"import type { IBeatmap, IHitObject, IBeatmapInfo } from \"../types/beatmap\";\nimport { GameMode, SampleSet } from \"../types/beatmap\";\nimport type { IBeatmapResources } from \"../types/resources\";\nimport { type Result, ErrorCode, ok, err } from \"../types/result\";\nimport { get_speed_multiplier } from \"../types/mods\";\nimport { OszLoader } from \"../parser/osz_loader\";\nimport { BeatmapParser, extract_preview_time } from \"../parser/beatmap_parser\";\nimport { BaseRenderer, DEFAULT_RENDERER_CONFIG, type IRendererConfig } from \"../renderer/base_renderer\";\nimport type { IRenderBackend } from \"../renderer/backend/render_backend\";\nimport { CanvasBackend } from \"../renderer/backend/canvas_backend\";\nimport { StandardRenderer } from \"../renderer/standard/standard_renderer\";\nimport { ManiaRenderer } from \"../renderer/mania/mania_renderer\";\nimport { AudioController } from \"./audio_controller\";\nimport { VideoController } from \"./video_controller\";\nimport { HitsoundController } from \"./hitsound_controller\";\nimport { type ISkinConfig, merge_skin } from \"../skin/skin_config\";\n\ntype PlayerEventMap = {\n timeupdate: [time: number, duration: number];\n ended: [];\n loaded: [beatmap: IBeatmap, resources: IBeatmapResources];\n error: [code: ErrorCode, reason: string];\n statechange: [is_playing: boolean];\n play: [];\n pause: [];\n seek: [time: number];\n};\n\ntype PlayerEvent = keyof PlayerEventMap;\n\nexport interface IKeyBindings {\n toggle_pause?: string; // default: Space\n seek_forward?: string; // default: ArrowRight\n seek_backward?: string; // default: ArrowLeft\n toggle_grid?: string; // default: g\n}\n\nexport interface IPlayerOptions {\n canvas: HTMLCanvasElement;\n skin?: Partial<ISkinConfig>;\n mods?: number;\n start_time?: number;\n autoplay?: boolean;\n volume?: number;\n backend?: IRenderBackend;\n renderer_config?: Partial<IRendererConfig>;\n playfield_scale?: number; // 0.0 to 1.0 (replaces fill_canvas)\n auto_resize?: boolean; // managed internally via ResizeObserver\n key_bindings?: IKeyBindings;\n}\n\nexport class BeatmapPlayer {\n private backend: IRenderBackend;\n private renderer: BaseRenderer | null = null;\n\n // audio system\n private audio_context: AudioContext;\n private audio: AudioController;\n private hitsounds: HitsoundController;\n private video: VideoController | null = null;\n\n private resources: IBeatmapResources | null = null;\n private animation_frame: number | null = null;\n\n private skin: ISkinConfig;\n private mods: number;\n private renderer_config: IRendererConfig;\n private start_offset: number;\n private volume: number;\n\n private listeners: Map<PlayerEvent, Set<Function>> = new Map();\n private _raw_osu_content: string = \"\";\n private _is_loaded: boolean = false;\n\n private next_hit_object_index: number = 0;\n\n private resize_observer: ResizeObserver | null = null;\n private key_handler: ((e: KeyboardEvent) => void) | null = null;\n private options: IPlayerOptions;\n\n constructor(options: IPlayerOptions) {\n this.options = options;\n this.backend = options.backend ?? new CanvasBackend();\n this.skin = merge_skin(options.skin);\n this.mods = options.mods ?? 0;\n this.renderer_config = { ...DEFAULT_RENDERER_CONFIG, ...options.renderer_config };\n\n // calculate scale and offset\n this.calculate_layout(options.canvas.width, options.canvas.height, options.playfield_scale);\n\n this.start_offset = options.start_time ?? -1;\n this.volume = options.volume ?? 0.5;\n\n // initialize backend with high dpi setting\n this.backend.initialize(options.canvas, this.renderer_config.use_high_dpi);\n\n // initialize audio system\n // @ts-ignore\n const AudioContextClass = window.AudioContext || window.webkitAudioContext;\n this.audio_context = new AudioContextClass();\n\n this.audio = new AudioController(this.audio_context);\n this.hitsounds = new HitsoundController(this.audio_context);\n\n // set initial volumes\n this.audio.set_volume(this.volume);\n this.hitsounds.set_volume(this.volume);\n\n if (options.auto_resize) {\n this.setup_auto_resize();\n }\n\n if (options.key_bindings) {\n this.setup_key_bindings(options.key_bindings);\n }\n }\n\n // load from .osz ArrayBuffer\n async load_osz(data: ArrayBuffer, difficulty?: number | string): Promise<Result<IBeatmapResources>> {\n try {\n const loader = new OszLoader();\n const result = await loader.load_osz(data, { difficulty });\n this.resources = result;\n return this.setup();\n } catch (e) {\n const reason = e instanceof Error ? e.message : String(e);\n this.emit(\"error\", ErrorCode.InvalidBeatmap, reason);\n return err(ErrorCode.InvalidBeatmap, reason);\n }\n }\n\n // load from file map (direct access)\n async load_files(files: Map<string, ArrayBuffer | string>, difficulty?: number | string): Promise<Result<IBeatmapResources>> {\n try {\n const loader = new OszLoader();\n this.resources = await loader.load_from_files(files, { difficulty });\n\n // store raw content for preview time extraction\n for (const [name, content] of files) {\n if (name.endsWith(\".osu\")) {\n this._raw_osu_content = typeof content === \"string\" ? content : new TextDecoder().decode(content);\n break;\n }\n }\n\n return this.setup();\n } catch (e) {\n const reason = e instanceof Error ? e.message : String(e);\n this.emit(\"error\", ErrorCode.InvalidBeatmap, reason);\n return err(ErrorCode.InvalidBeatmap, reason);\n }\n }\n\n async load_hitsounds(files: Map<string, ArrayBuffer>): Promise<void> {\n try {\n await this.hitsounds.load_samples(files);\n } catch (e) {\n console.error(\"[BeatmapPlayer] Failed to load hitsounds:\", e);\n }\n }\n\n async load_beatmap(\n beatmap: IBeatmap,\n audio?: ArrayBuffer,\n background?: Blob,\n video?: Blob,\n video_offset?: number\n ): Promise<Result<IBeatmapResources>> {\n this.resources = {\n beatmap,\n available_difficulties: [],\n files: new Map(),\n audio,\n background,\n video,\n video_offset\n };\n return this.setup();\n }\n\n async load_osu_content(content: string, audio?: ArrayBuffer): Promise<Result<IBeatmapResources>> {\n try {\n const parser = new BeatmapParser();\n const beatmap = parser.parse(content);\n this._raw_osu_content = content;\n return this.load_beatmap(beatmap, audio);\n } catch (e) {\n const reason = e instanceof Error ? e.message : String(e);\n this.emit(\"error\", ErrorCode.InvalidBeatmap, reason);\n return err(ErrorCode.InvalidBeatmap, reason);\n }\n }\n\n private async setup(): Promise<Result<IBeatmapResources>> {\n if (!this.resources) {\n return err(ErrorCode.NotLoaded, \"No resources loaded\");\n }\n\n const { beatmap, audio, video, video_offset } = this.resources;\n const speed = get_speed_multiplier(this.mods);\n\n // setup audio\n if (audio) {\n try {\n await this.audio.load(audio, this.mods);\n } catch (e) {\n const reason = e instanceof Error ? e.message : String(e);\n this.emit(\"error\", ErrorCode.AudioDecodeError, reason);\n return err(ErrorCode.AudioDecodeError, reason);\n }\n }\n\n // setup video\n if (video) {\n this.video = new VideoController();\n await this.video.load(video, video_offset ?? 0, speed);\n }\n\n // create renderer based on mode\n try {\n this.renderer = this.create_renderer(beatmap);\n this.renderer.initialize(beatmap);\n } catch (e) {\n const reason = e instanceof Error ? e.message : String(e);\n this.emit(\"error\", ErrorCode.UnsupportedMode, reason);\n return err(ErrorCode.UnsupportedMode, reason);\n }\n\n // determine start time from preview point\n if (this.start_offset < 0 && this._raw_osu_content) {\n const preview = extract_preview_time(this._raw_osu_content);\n this.start_offset = preview > 0 ? preview : this.get_last_object_time() * 0.42;\n }\n if (this.start_offset < 0) {\n this.start_offset = 0;\n }\n\n // ensure start index is correct\n this.update_hit_index(this.start_offset);\n\n if (this.resources?.background) {\n try {\n const img = new Image();\n img.src = URL.createObjectURL(this.resources.background);\n await img.decode();\n this.renderer.set_background({\n source: img,\n width: img.width,\n height: img.height\n });\n\n // ensure we are ready to draw\n this._is_loaded = true;\n requestAnimationFrame(() => this.render_frame(this.start_offset));\n } catch (e) {\n console.warn(\"[BeatmapPlayer] Failed to load background\", e);\n }\n }\n\n this._is_loaded = true;\n this.emit(\"loaded\", beatmap, this.resources);\n\n // final render call to be sure\n requestAnimationFrame(() => this.render_frame(this.start_offset));\n\n return ok(this.resources);\n }\n\n private create_renderer(beatmap: IBeatmap): BaseRenderer {\n switch (beatmap.mode) {\n case GameMode.Standard:\n return new StandardRenderer(this.backend, this.skin, this.mods, this.renderer_config);\n case GameMode.Mania:\n return new ManiaRenderer(this.backend, this.skin, this.mods, this.renderer_config);\n case GameMode.Taiko:\n case GameMode.Catch:\n default:\n throw new Error(`Unsupported game mode: ${GameMode[beatmap.mode] ?? beatmap.mode}`);\n }\n }\n\n private get_last_object_time(): number {\n if (!this.resources?.beatmap.objects.length) return 0;\n const objects = this.resources.beatmap.objects;\n return objects[objects.length - 1].end_time;\n }\n\n async play(): Promise<void> {\n if (!this.renderer || !this._is_loaded) {\n console.warn(\"[BeatmapPlayer] Cannot play: not loaded\");\n return;\n }\n\n if (this.audio.is_playing) {\n return;\n }\n\n // resume audio context if suspended (browser requirement)\n if (this.audio_context.state === \"suspended\") {\n await this.audio_context.resume();\n }\n\n this.audio.play(this.start_offset);\n this.video?.play();\n this.start_render_loop();\n this.emit(\"play\");\n this.emit(\"statechange\", true);\n }\n\n pause(): void {\n if (!this.audio.is_playing) return;\n\n // save current position for resume\n this.start_offset = this.audio.current_time;\n\n this.audio.pause();\n this.video?.pause();\n this.stop_render_loop();\n this.emit(\"pause\");\n this.emit(\"statechange\", false);\n }\n\n set_mods(mods: number): void {\n this.mods = mods;\n const speed = get_speed_multiplier(mods);\n\n this.renderer?.set_mods(mods);\n this.audio.set_speed(speed);\n this.video?.set_speed(speed);\n\n if (this._is_loaded) {\n requestAnimationFrame(() => this.render_frame(this.current_time));\n }\n }\n\n seek(time_ms: number): void {\n // update start offset for both playing and paused states\n this.start_offset = Math.max(0, Math.min(time_ms, this.duration));\n\n // update hit index to avoid replaying hits or missing future hits\n this.update_hit_index(this.start_offset);\n\n this.audio.seek(this.start_offset);\n this.video?.seek(this.start_offset);\n\n this.emit(\"seek\", this.start_offset);\n\n // render frame at new position\n this.render_frame(this.start_offset);\n }\n\n async set_difficulty(index: number | string): Promise<Result<IBeatmapResources>> {\n if (!this.resources) {\n return err(ErrorCode.NotLoaded, \"No beatmap resources loaded\");\n }\n\n const was_playing = this.is_playing;\n this.stop();\n\n try {\n const loader = new OszLoader();\n // preserve existing files and options, just change difficulty\n const result = await loader.load_from_files(this.resources.files, { difficulty: index });\n this.resources = result;\n\n // update raw content for preview time extraction\n const selected_file = this.resources.available_difficulties.find((d) => d.version === this.resources!.beatmap.version)?.filename;\n if (selected_file) {\n const content = this.resources.files.get(selected_file);\n if (content) {\n this._raw_osu_content = typeof content === \"string\" ? content : new TextDecoder().decode(content);\n }\n }\n\n const setup_result = await this.setup();\n\n if (setup_result.success && was_playing) {\n this.play();\n }\n\n return setup_result;\n } catch (e) {\n const reason = e instanceof Error ? e.message : String(e);\n this.emit(\"error\", ErrorCode.InvalidBeatmap, reason);\n return err(ErrorCode.InvalidBeatmap, reason);\n }\n }\n\n private update_hit_index(time: number): void {\n if (!this.resources?.beatmap) return;\n\n const objects = this.resources.beatmap.objects;\n\n // reset index if we went backwards\n if (this.next_hit_object_index > 0 && objects[this.next_hit_object_index - 1].time > time) {\n this.next_hit_object_index = 0;\n }\n\n // fast forward\n while (this.next_hit_object_index < objects.length && objects[this.next_hit_object_index].time < time) {\n this.next_hit_object_index++;\n }\n }\n\n stop(): void {\n this.pause();\n this.start_offset = 0;\n this.audio.seek(0);\n this.update_hit_index(0);\n this.render_frame(0);\n }\n\n dispose(): void {\n this.stop();\n this.backend.dispose();\n this.audio.dispose();\n this.hitsounds.dispose();\n this.video?.dispose();\n this.renderer?.dispose(); // Ensure renderer is disposed\n this.listeners.clear();\n\n if (this.resize_observer) {\n this.resize_observer.disconnect();\n this.resize_observer = null;\n }\n\n if (this.key_handler) {\n window.removeEventListener(\"keydown\", this.key_handler);\n this.key_handler = null;\n }\n\n if (this.audio_context && this.audio_context.state !== \"closed\") {\n this.audio_context.close().catch(() => {});\n }\n\n this.renderer = null;\n this.resources = null;\n this._is_loaded = false;\n this.listeners.clear();\n }\n\n // getters\n get current_time(): number {\n return this.audio.current_time;\n }\n\n get duration(): number {\n return this.audio.duration || this.get_last_object_time();\n }\n\n get is_playing(): boolean {\n return this.audio.is_playing;\n }\n\n get is_loaded(): boolean {\n return this._is_loaded;\n }\n\n get mode(): string {\n if (!this.resources) return \"standard\";\n switch (this.resources.beatmap.mode) {\n case 1:\n return \"taiko\";\n case 2:\n return \"catch\";\n case 3:\n return \"mania\";\n default:\n return \"standard\";\n }\n }\n\n get beatmap(): IBeatmap | null {\n return this.resources?.beatmap ?? null;\n }\n\n get available_difficulties(): IBeatmapInfo[] {\n return this.resources?.available_difficulties ?? [];\n }\n\n get background(): Blob | undefined {\n return this.resources?.background;\n }\n\n get config(): IRendererConfig {\n return this.renderer_config;\n }\n\n resize(width: number, height: number, playfield_scale?: number): void {\n this.backend.resize(width, height);\n this.calculate_layout(width, height, playfield_scale);\n\n if (this._is_loaded) {\n requestAnimationFrame(() => this.render_frame(this.current_time));\n }\n }\n\n update_config(config: Partial<IRendererConfig>): void {\n this.renderer_config = { ...this.renderer_config, ...config };\n this.renderer?.update_config(this.renderer_config);\n\n if (this._is_loaded) {\n requestAnimationFrame(() => this.render_frame(this.current_time));\n }\n }\n\n set_skin(skin: Partial<ISkinConfig>): void {\n this.skin = merge_skin(skin);\n\n // renderer needs to be recreated with new skin\n if (this._is_loaded && this.resources?.beatmap) {\n this.renderer = this.create_renderer(this.resources.beatmap);\n this.renderer.initialize(this.resources.beatmap);\n requestAnimationFrame(() => this.render_frame(this.current_time));\n }\n }\n\n private setup_auto_resize(): void {\n this.resize_observer = new ResizeObserver(() => {\n const canvas = this.options.canvas;\n const parent = canvas.parentElement;\n if (parent) {\n const rect = parent.getBoundingClientRect();\n // do not manually set canvas.width/height here,\n // let this.resize -> backend.resize handle it with DPR\n this.resize(rect.width, rect.height, this.options.playfield_scale);\n }\n });\n this.resize_observer.observe(this.options.canvas.parentElement || this.options.canvas);\n }\n\n private setup_key_bindings(bindings: IKeyBindings): void {\n this.key_handler = (e: KeyboardEvent) => {\n const keys = {\n toggle_pause: bindings.toggle_pause ?? \"Space\",\n seek_forward: bindings.seek_forward ?? \"ArrowRight\",\n seek_backward: bindings.seek_backward ?? \"ArrowLeft\",\n toggle_grid: bindings.toggle_grid ?? \"g\"\n };\n\n if (e.code === keys.toggle_pause) {\n e.preventDefault();\n this.toggle_pause();\n } else if (e.code === keys.seek_forward) {\n e.preventDefault();\n this.seek(this.current_time + 5000);\n } else if (e.code === keys.seek_backward) {\n e.preventDefault();\n this.seek(this.current_time - 5000);\n } else if (e.code === keys.toggle_grid) {\n this.toggle_grid();\n }\n };\n\n window.addEventListener(\"keydown\", this.key_handler);\n }\n\n toggle_pause(): void {\n if (!this._is_loaded) return;\n this.is_playing ? this.pause() : this.play();\n }\n\n toggle_grid(): void {\n if (this.renderer_config.grid_level === 0) {\n this.renderer_config.grid_level = 32;\n } else {\n this.renderer_config.grid_level = 0;\n }\n this.render_frame(this.current_time);\n }\n\n private calculate_layout(width: number, height: number, playfield_scale?: number): void {\n const target_width = 512;\n const target_height = 384;\n\n let fill = 0.9;\n if (typeof playfield_scale === \"number\") {\n fill = playfield_scale;\n }\n\n // calculate scale based on the smaller dimension to fit playfield\n const scale_x = (width * fill) / target_width;\n const scale_y = (height * fill) / target_height;\n const scale = Math.min(scale_x, scale_y);\n\n this.renderer_config.scale = scale;\n // pixel-perfect centering\n this.renderer_config.offset_x = Math.floor((width - target_width * scale) / 2);\n this.renderer_config.offset_y = Math.floor((height - target_height * scale) / 2);\n\n // propagate config to renderer\n if (this.renderer) {\n this.renderer.update_config(this.renderer_config);\n }\n }\n\n set_volume(volume: number): void {\n this.volume = volume;\n this.audio.set_volume(volume);\n this.hitsounds.set_volume(volume);\n }\n\n on<E extends PlayerEvent>(event: E, callback: (...args: PlayerEventMap[E]) => void): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(callback);\n }\n\n off<E extends PlayerEvent>(event: E, callback: Function): void {\n this.listeners.get(event)?.delete(callback);\n }\n\n private emit<E extends PlayerEvent>(event: E, ...args: PlayerEventMap[E]): void {\n const callbacks = this.listeners.get(event);\n if (callbacks) {\n for (const cb of callbacks) {\n (cb as Function)(...args);\n }\n }\n }\n\n private start_render_loop(): void {\n if (this.animation_frame !== null) return;\n\n const loop = () => {\n if (!this.audio.is_playing) {\n this.animation_frame = null;\n return;\n }\n\n const time = this.audio.current_time;\n\n // process hitsounds\n this.schedule_hitsounds();\n\n this.render_frame(time);\n this.video?.sync(time);\n this.emit(\"timeupdate\", time, this.duration);\n\n if (time >= this.duration) {\n this.emit(\"ended\");\n this.stop_render_loop();\n this.emit(\"statechange\", false);\n return;\n }\n\n this.animation_frame = requestAnimationFrame(loop);\n };\n\n this.animation_frame = requestAnimationFrame(loop);\n }\n\n private schedule_hitsounds(): void {\n if (!this.resources?.beatmap || !this.audio.is_playing) return;\n\n const objects = this.resources.beatmap.objects;\n const current_time = this.audio.current_time;\n const lookahead = 100;\n const schedule_window = current_time + lookahead;\n\n while (this.next_hit_object_index < objects.length && objects[this.next_hit_object_index].time <= schedule_window) {\n const obj = objects[this.next_hit_object_index];\n\n // only play if it hasn't passed by too much\n // but we rely on update_hit_index to skip old ones on seek\n if (obj.time >= current_time - 20) {\n this.play_hitsound(obj);\n }\n\n this.next_hit_object_index++;\n }\n }\n\n private play_hitsound(obj: IHitObject): void {\n const timing = this.get_timing_point(obj.time);\n\n // default values from timing point\n let volume = timing.volume;\n let normal_set = timing.sample_set;\n let addition_set = timing.sample_set; // Additions default to current set\n let index = timing.sample_index;\n let custom_filename: string | undefined = undefined;\n\n // override from HitObject specific HitSample\n if (obj.hit_sample) {\n const sample = obj.hit_sample;\n\n if (sample.normal_set !== SampleSet.Auto) {\n normal_set = sample.normal_set;\n // if normal set is explicitly set, addition set defaults to it (if Auto)\n if (sample.addition_set === SampleSet.Auto) {\n addition_set = normal_set;\n }\n }\n\n if (sample.addition_set !== SampleSet.Auto) {\n addition_set = sample.addition_set;\n }\n\n if (sample.index !== 0) index = sample.index;\n if (sample.volume !== 0) volume = sample.volume;\n custom_filename = sample.filename;\n }\n\n // fallbacks for Auto values\n if (normal_set === SampleSet.Auto) normal_set = SampleSet.Normal;\n if (addition_set === SampleSet.Auto) addition_set = normal_set;\n\n // calculate exact AudioContext time for this object\n const when = this.audio.get_host_time(obj.time);\n\n this.hitsounds.play(normal_set, addition_set, obj.hit_sound, index, volume, custom_filename, when);\n }\n\n private get_timing_point(time: number): any {\n const points = this.resources?.beatmap.timing_points ?? [];\n for (let i = points.length - 1; i >= 0; i--) {\n if (points[i].time <= time) return points[i];\n }\n return points[0]; // fallback\n }\n\n private stop_render_loop(): void {\n if (this.animation_frame !== null) {\n cancelAnimationFrame(this.animation_frame);\n this.animation_frame = null;\n }\n }\n\n private render_frame(time: number): void {\n this.backend.clear();\n this.renderer?.render(time);\n }\n}\n"
|
|
32
|
+
"import type { IBeatmap, IHitObject, IBeatmapInfo } from \"../types/beatmap\";\nimport { GameMode, SampleSet } from \"../types/beatmap\";\nimport type { IBeatmapResources } from \"../types/resources\";\nimport { type Result, ErrorCode, ok, err } from \"../types/result\";\nimport { get_speed_multiplier } from \"../types/mods\";\nimport { OszLoader } from \"../parser/osz_loader\";\nimport { get_shared_parser } from \"../parser/async_parser\";\nimport { BaseRenderer, DEFAULT_RENDERER_CONFIG, type IRendererConfig } from \"../renderer/base_renderer\";\nimport type { IRenderBackend } from \"../renderer/backend/render_backend\";\nimport { CanvasBackend } from \"../renderer/backend/canvas_backend\";\nimport { StandardRenderer } from \"../renderer/standard/standard_renderer\";\nimport { ManiaRenderer } from \"../renderer/mania/mania_renderer\";\nimport { AudioController } from \"./audio_controller\";\nimport { VideoController } from \"./video_controller\";\nimport { HitsoundController } from \"./hitsound_controller\";\nimport { type ISkinConfig, merge_skin } from \"../skin/skin_config\";\n\ntype PlayerEventMap = {\n timeupdate: [time: number, duration: number];\n ended: [];\n loaded: [beatmap: IBeatmap, resources: IBeatmapResources];\n error: [code: ErrorCode, reason: string];\n statechange: [is_playing: boolean];\n play: [];\n pause: [];\n seek: [time: number];\n};\n\ntype PlayerEvent = keyof PlayerEventMap;\n\nexport interface IPlayerOptions {\n canvas: HTMLCanvasElement;\n skin?: Partial<ISkinConfig>;\n mods?: number;\n start_time?: number;\n autoplay?: boolean;\n volume?: number;\n backend?: IRenderBackend;\n renderer_config?: Partial<IRendererConfig>;\n playfield_scale?: number;\n auto_resize?: boolean;\n enable_fps_counter?: boolean;\n}\n\nexport class BeatmapPlayer {\n private backend: IRenderBackend;\n private renderer: BaseRenderer | null = null;\n\n // audio system\n private audio_context: AudioContext;\n private audio: AudioController;\n private hitsounds: HitsoundController;\n private video: VideoController | null = null;\n\n private resources: IBeatmapResources | null = null;\n private animation_frame: number | null = null;\n\n private skin: ISkinConfig;\n private mods: number;\n private renderer_config: IRendererConfig;\n private start_offset: number;\n private volume: number;\n\n private listeners: Map<PlayerEvent, Set<Function>> = new Map();\n private _raw_osu_content: string = \"\";\n private _is_loaded: boolean = false;\n\n private next_hit_object_index: number = 0;\n\n private resize_observer: ResizeObserver | null = null;\n private key_handler: ((e: KeyboardEvent) => void) | null = null;\n private options: IPlayerOptions;\n\n // fps tracking\n private enable_fps_counter = false;\n private fps_frame_count = 0;\n private fps_last_update = 0;\n private current_fps = 0;\n\n constructor(options: IPlayerOptions) {\n this.options = options;\n this.backend = options.backend ?? new CanvasBackend();\n this.skin = merge_skin(options.skin);\n this.mods = options.mods ?? 0;\n this.renderer_config = { ...DEFAULT_RENDERER_CONFIG, ...options.renderer_config };\n\n // calculate scale and offset\n this.calculate_layout(options.canvas.width, options.canvas.height, options.playfield_scale);\n\n this.start_offset = options.start_time ?? -1;\n this.volume = options.volume ?? 0.5;\n\n // initialize backend with high dpi setting\n this.backend.initialize(options.canvas, this.renderer_config.use_high_dpi);\n\n // initialize audio system\n // @ts-ignore\n const audio_context_class = window.AudioContext || window.webkitAudioContext;\n this.audio_context = new audio_context_class();\n\n this.audio = new AudioController(this.audio_context);\n this.hitsounds = new HitsoundController(this.audio_context);\n\n // set initial volumes\n this.audio.set_volume(this.volume);\n this.hitsounds.set_volume(this.volume);\n\n if (options.auto_resize) {\n this.setup_auto_resize();\n }\n\n this.enable_fps_counter = options.enable_fps_counter ?? false;\n this.fps_last_update = performance.now();\n }\n\n // load from .osz ArrayBuffer\n async load_osz(data: ArrayBuffer, difficulty?: number | string): Promise<Result<IBeatmapResources>> {\n try {\n const loader = new OszLoader();\n const result = await loader.load_osz(data, { difficulty });\n this.resources = result;\n return this.setup();\n } catch (e) {\n const reason = e instanceof Error ? e.message : String(e);\n this.emit(\"error\", ErrorCode.InvalidBeatmap, reason);\n return err(ErrorCode.InvalidBeatmap, reason);\n }\n }\n\n // load from file map (direct access)\n async load_files(files: Map<string, ArrayBuffer | string>, difficulty?: number | string): Promise<Result<IBeatmapResources>> {\n try {\n const loader = new OszLoader();\n this.resources = await loader.load_from_files(files, { difficulty });\n\n // store raw content for preview time extraction\n for (const [name, content] of files) {\n if (name.endsWith(\".osu\")) {\n this._raw_osu_content = typeof content === \"string\" ? content : new TextDecoder().decode(content);\n break;\n }\n }\n\n return this.setup();\n } catch (e) {\n const reason = e instanceof Error ? e.message : String(e);\n this.emit(\"error\", ErrorCode.InvalidBeatmap, reason);\n return err(ErrorCode.InvalidBeatmap, reason);\n }\n }\n\n async load_hitsounds(files: Map<string, ArrayBuffer>): Promise<void> {\n try {\n await this.hitsounds.load_samples(files);\n } catch (e) {\n console.error(\"[BeatmapPlayer] Failed to load hitsounds:\", e);\n }\n }\n\n async load_beatmap(\n beatmap: IBeatmap,\n audio?: ArrayBuffer,\n background?: Blob,\n video?: Blob,\n video_offset?: number\n ): Promise<Result<IBeatmapResources>> {\n this.resources = {\n beatmap,\n available_difficulties: [],\n files: new Map(),\n audio,\n background,\n video,\n video_offset\n };\n return this.setup();\n }\n\n async load_osu_content(content: string, audio?: ArrayBuffer): Promise<Result<IBeatmapResources>> {\n try {\n const parser = get_shared_parser();\n const beatmap = await parser.parse(content);\n this._raw_osu_content = content;\n return this.load_beatmap(beatmap, audio);\n } catch (e) {\n const reason = e instanceof Error ? e.message : String(e);\n this.emit(\"error\", ErrorCode.InvalidBeatmap, reason);\n return err(ErrorCode.InvalidBeatmap, reason);\n }\n }\n\n private async setup(): Promise<Result<IBeatmapResources>> {\n if (!this.resources) {\n return err(ErrorCode.NotLoaded, \"No resources loaded\");\n }\n\n const { beatmap, audio, video, video_offset } = this.resources;\n const speed = get_speed_multiplier(this.mods);\n\n // setup audio\n if (audio) {\n try {\n await this.audio.load(audio, this.mods);\n } catch (e) {\n const reason = e instanceof Error ? e.message : String(e);\n this.emit(\"error\", ErrorCode.AudioDecodeError, reason);\n return err(ErrorCode.AudioDecodeError, reason);\n }\n }\n\n // setup video\n if (video) {\n this.video = new VideoController();\n await this.video.load(video, video_offset ?? 0, speed);\n }\n\n // create renderer based on mode\n try {\n this.renderer = this.create_renderer(beatmap);\n this.renderer.initialize(beatmap);\n } catch (e) {\n const reason = e instanceof Error ? e.message : String(e);\n this.emit(\"error\", ErrorCode.UnsupportedMode, reason);\n return err(ErrorCode.UnsupportedMode, reason);\n }\n\n // determine start time from preview point\n if (this.start_offset < 0 && this._raw_osu_content) {\n const parser = get_shared_parser();\n const preview = await parser.extract_preview_time(this._raw_osu_content);\n this.start_offset = preview > 0 ? preview : this.get_last_object_time() * 0.42;\n }\n if (this.start_offset < 0) {\n this.start_offset = 0;\n }\n\n // ensure start index is correct\n this.update_hit_index(this.start_offset);\n\n if (this.resources?.background) {\n try {\n const img = new Image();\n img.src = URL.createObjectURL(this.resources.background);\n await img.decode();\n this.renderer.set_background({\n source: img,\n width: img.width,\n height: img.height\n });\n\n // ensure we are ready to draw\n this._is_loaded = true;\n requestAnimationFrame(() => this.render_frame(this.start_offset));\n } catch (e) {\n console.warn(\"[BeatmapPlayer] Failed to load background\", e);\n }\n }\n\n this._is_loaded = true;\n this.emit(\"loaded\", beatmap, this.resources);\n\n // final render call to be sure\n requestAnimationFrame(() => this.render_frame(this.start_offset));\n\n return ok(this.resources);\n }\n\n private create_renderer(beatmap: IBeatmap): BaseRenderer {\n switch (beatmap.mode) {\n case GameMode.Standard:\n return new StandardRenderer(this.backend, this.skin, this.mods, this.renderer_config);\n case GameMode.Mania:\n return new ManiaRenderer(this.backend, this.skin, this.mods, this.renderer_config);\n case GameMode.Taiko:\n case GameMode.Catch:\n default:\n throw new Error(`Unsupported game mode: ${GameMode[beatmap.mode] ?? beatmap.mode}`);\n }\n }\n\n private get_last_object_time(): number {\n if (!this.resources?.beatmap.objects.length) return 0;\n const objects = this.resources.beatmap.objects;\n return objects[objects.length - 1].end_time;\n }\n\n async play(): Promise<void> {\n if (!this.renderer || !this._is_loaded) {\n console.warn(\"[BeatmapPlayer] Cannot play: not loaded\");\n return;\n }\n\n if (this.audio.is_playing) {\n return;\n }\n\n // resume audio context if suspended (browser requirement)\n if (this.audio_context.state === \"suspended\") {\n await this.audio_context.resume();\n }\n\n this.audio.play(this.start_offset);\n this.video?.play();\n this.start_render_loop();\n this.emit(\"play\");\n this.emit(\"statechange\", true);\n }\n\n pause(): void {\n if (!this.audio.is_playing) return;\n\n // save current position for resume\n this.start_offset = this.audio.current_time;\n\n this.audio.pause();\n this.video?.pause();\n this.stop_render_loop();\n this.emit(\"pause\");\n this.emit(\"statechange\", false);\n }\n\n set_mods(mods: number): void {\n this.mods = mods;\n const speed = get_speed_multiplier(mods);\n\n this.renderer?.set_mods(mods);\n this.audio.set_speed(speed);\n this.video?.set_speed(speed);\n\n if (this._is_loaded) {\n requestAnimationFrame(() => this.render_frame(this.current_time));\n }\n }\n\n seek(time_ms: number): void {\n // update start offset for both playing and paused states\n this.start_offset = Math.max(0, Math.min(time_ms, this.duration));\n\n // update hit index to avoid replaying hits or missing future hits\n this.update_hit_index(this.start_offset);\n\n this.audio.seek(this.start_offset);\n this.video?.seek(this.start_offset);\n\n this.emit(\"seek\", this.start_offset);\n\n // render frame at new position\n this.render_frame(this.start_offset);\n }\n\n async set_difficulty(index: number | string): Promise<Result<IBeatmapResources>> {\n if (!this.resources) {\n return err(ErrorCode.NotLoaded, \"No beatmap resources loaded\");\n }\n\n const was_playing = this.is_playing;\n this.stop();\n\n try {\n const loader = new OszLoader();\n // preserve existing files and options, just change difficulty\n const result = await loader.load_from_files(this.resources.files, { difficulty: index });\n this.resources = result;\n\n // update raw content for preview time extraction\n const selected_file = this.resources.available_difficulties.find((d) => d.version === this.resources!.beatmap.version)?.filename;\n if (selected_file) {\n const content = this.resources.files.get(selected_file);\n if (content) {\n this._raw_osu_content = typeof content === \"string\" ? content : new TextDecoder().decode(content);\n }\n }\n\n const setup_result = await this.setup();\n\n if (setup_result.success && was_playing) {\n this.play();\n }\n\n return setup_result;\n } catch (e) {\n const reason = e instanceof Error ? e.message : String(e);\n this.emit(\"error\", ErrorCode.InvalidBeatmap, reason);\n return err(ErrorCode.InvalidBeatmap, reason);\n }\n }\n\n private update_hit_index(time: number): void {\n if (!this.resources?.beatmap) return;\n\n const objects = this.resources.beatmap.objects;\n\n // reset index if we went backwards\n if (this.next_hit_object_index > 0 && objects[this.next_hit_object_index - 1].time > time) {\n this.next_hit_object_index = 0;\n }\n\n // fast forward\n while (this.next_hit_object_index < objects.length && objects[this.next_hit_object_index].time < time) {\n this.next_hit_object_index++;\n }\n }\n\n stop(): void {\n this.pause();\n this.start_offset = 0;\n this.audio.seek(0);\n this.update_hit_index(0);\n this.render_frame(0);\n }\n\n dispose(): void {\n this.stop();\n this.backend.dispose();\n this.audio.dispose();\n this.hitsounds.dispose();\n this.video?.dispose();\n this.renderer?.dispose(); // Ensure renderer is disposed\n this.listeners.clear();\n\n if (this.resize_observer) {\n this.resize_observer.disconnect();\n this.resize_observer = null;\n }\n\n if (this.key_handler) {\n window.removeEventListener(\"keydown\", this.key_handler);\n this.key_handler = null;\n }\n\n if (this.audio_context && this.audio_context.state !== \"closed\") {\n this.audio_context.close().catch(() => {});\n }\n\n this.renderer = null;\n this.resources = null;\n this._is_loaded = false;\n this.listeners.clear();\n }\n\n // getters\n get current_time(): number {\n return this.audio.current_time;\n }\n\n get duration(): number {\n return this.audio.duration || this.get_last_object_time();\n }\n\n get is_playing(): boolean {\n return this.audio.is_playing;\n }\n\n get is_loaded(): boolean {\n return this._is_loaded;\n }\n\n get mode(): string {\n if (!this.resources) return \"standard\";\n switch (this.resources.beatmap.mode) {\n case 1:\n return \"taiko\";\n case 2:\n return \"catch\";\n case 3:\n return \"mania\";\n default:\n return \"standard\";\n }\n }\n\n get beatmap(): IBeatmap | null {\n return this.resources?.beatmap ?? null;\n }\n\n get available_difficulties(): IBeatmapInfo[] {\n return this.resources?.available_difficulties ?? [];\n }\n\n get background(): Blob | undefined {\n return this.resources?.background;\n }\n\n get config(): IRendererConfig {\n return this.renderer_config;\n }\n\n resize(width: number, height: number, playfield_scale?: number): void {\n this.backend.resize(width, height);\n this.calculate_layout(width, height, playfield_scale);\n\n if (this._is_loaded) {\n requestAnimationFrame(() => this.render_frame(this.current_time));\n }\n }\n\n update_config(config: Partial<IRendererConfig>): void {\n this.renderer_config = { ...this.renderer_config, ...config };\n this.renderer?.update_config(this.renderer_config);\n\n if (this._is_loaded) {\n requestAnimationFrame(() => this.render_frame(this.current_time));\n }\n }\n\n set_skin(skin: Partial<ISkinConfig>): void {\n this.skin = merge_skin(skin);\n\n // renderer needs to be recreated with new skin\n if (this._is_loaded && this.resources?.beatmap) {\n this.renderer = this.create_renderer(this.resources.beatmap);\n this.renderer.initialize(this.resources.beatmap);\n requestAnimationFrame(() => this.render_frame(this.current_time));\n }\n }\n\n private setup_auto_resize(): void {\n this.resize_observer = new ResizeObserver(() => {\n const canvas = this.options.canvas;\n const parent = canvas.parentElement;\n if (parent) {\n const rect = parent.getBoundingClientRect();\n // do not manually set canvas.width/height here,\n // let this.resize -> backend.resize handle it with DPR\n this.resize(rect.width, rect.height, this.options.playfield_scale);\n }\n });\n this.resize_observer.observe(this.options.canvas.parentElement || this.options.canvas);\n }\n\n toggle_pause(): void {\n if (!this._is_loaded) return;\n this.is_playing ? this.pause() : this.play();\n }\n\n toggle_grid(): void {\n if (this.renderer_config.grid_level === 0) {\n this.renderer_config.grid_level = 32;\n } else {\n this.renderer_config.grid_level = 0;\n }\n this.render_frame(this.current_time);\n }\n\n private calculate_layout(width: number, height: number, playfield_scale?: number): void {\n const target_width = 512;\n const target_height = 384;\n\n let fill = 0.9;\n if (typeof playfield_scale === \"number\") {\n fill = playfield_scale;\n }\n\n // calculate scale based on the smaller dimension to fit playfield\n const scale_x = (width * fill) / target_width;\n const scale_y = (height * fill) / target_height;\n const scale = Math.min(scale_x, scale_y);\n\n this.renderer_config.scale = scale;\n // pixel-perfect centering\n this.renderer_config.offset_x = Math.floor((width - target_width * scale) / 2);\n this.renderer_config.offset_y = Math.floor((height - target_height * scale) / 2);\n\n // propagate config to renderer\n if (this.renderer) {\n this.renderer.update_config(this.renderer_config);\n }\n }\n\n set_volume(volume: number): void {\n this.volume = volume;\n this.audio.set_volume(volume);\n this.hitsounds.set_volume(volume);\n }\n\n on<E extends PlayerEvent>(event: E, callback: (...args: PlayerEventMap[E]) => void): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(callback);\n }\n\n off<E extends PlayerEvent>(event: E, callback: Function): void {\n this.listeners.get(event)?.delete(callback);\n }\n\n private emit<E extends PlayerEvent>(event: E, ...args: PlayerEventMap[E]): void {\n const callbacks = this.listeners.get(event);\n if (callbacks) {\n for (const cb of callbacks) {\n (cb as Function)(...args);\n }\n }\n }\n\n private last_timestamp: number = 0;\n private smooth_time: number = 0;\n\n private start_render_loop(): void {\n if (this.animation_frame !== null) return;\n\n this.last_timestamp = performance.now();\n this.smooth_time = this.audio.current_time;\n\n const loop = (timestamp: number) => {\n if (!this.audio.is_playing) {\n this.animation_frame = null;\n return;\n }\n\n // calculate smooth time\n const delta = timestamp - this.last_timestamp;\n this.last_timestamp = timestamp;\n\n // advance smooth time by delta * speed\n this.smooth_time += delta * this.audio.speed_multiplier;\n\n // resync with audio clock if deviation is too large (> 30ms)\n // or periodically to prevent drift\n const actual_audio_time = this.audio.current_time;\n const deviation = Math.abs(this.smooth_time - actual_audio_time);\n\n if (deviation > 30) {\n this.smooth_time = actual_audio_time;\n } else {\n // slowly nudge smooth_time towards actual_audio_time to prevent drift\n this.smooth_time += (actual_audio_time - this.smooth_time) * 0.1;\n }\n\n const time = this.smooth_time;\n\n // process hitsounds\n this.schedule_hitsounds();\n\n this.render_frame(time);\n this.video?.sync(time);\n this.emit(\"timeupdate\", time, this.duration);\n\n if (time >= this.duration) {\n this.emit(\"ended\");\n this.stop_render_loop();\n this.emit(\"statechange\", false);\n return;\n }\n\n this.animation_frame = requestAnimationFrame(loop);\n };\n\n this.animation_frame = requestAnimationFrame(loop);\n }\n\n private schedule_hitsounds(): void {\n if (!this.resources?.beatmap || !this.audio.is_playing) return;\n\n const objects = this.resources.beatmap.objects;\n const current_time = this.audio.current_time;\n const lookahead = 100;\n const schedule_window = current_time + lookahead;\n\n while (this.next_hit_object_index < objects.length && objects[this.next_hit_object_index].time <= schedule_window) {\n const obj = objects[this.next_hit_object_index];\n\n // only play if it hasn't passed by too much\n // but we rely on update_hit_index to skip old ones on seek\n if (obj.time >= current_time - 20) {\n this.play_hitsound(obj);\n }\n\n this.next_hit_object_index++;\n }\n }\n\n private play_hitsound(obj: IHitObject): void {\n const timing = this.get_timing_point(obj.time);\n\n // default values from timing point\n let volume = timing.volume;\n let normal_set = timing.sample_set;\n let addition_set = timing.sample_set; // Additions default to current set\n let index = timing.sample_index;\n let custom_filename: string | undefined = undefined;\n\n // override from HitObject specific HitSample\n if (obj.hit_sample) {\n const sample = obj.hit_sample;\n\n if (sample.normal_set !== SampleSet.Auto) {\n normal_set = sample.normal_set;\n // if normal set is explicitly set, addition set defaults to it (if Auto)\n if (sample.addition_set === SampleSet.Auto) {\n addition_set = normal_set;\n }\n }\n\n if (sample.addition_set !== SampleSet.Auto) {\n addition_set = sample.addition_set;\n }\n\n if (sample.index !== 0) index = sample.index;\n if (sample.volume !== 0) volume = sample.volume;\n custom_filename = sample.filename;\n }\n\n // fallbacks for Auto values\n if (normal_set === SampleSet.Auto) normal_set = SampleSet.Normal;\n if (addition_set === SampleSet.Auto) addition_set = normal_set;\n\n // calculate exact AudioContext time for this object\n const when = this.audio.get_host_time(obj.time);\n\n this.hitsounds.play(normal_set, addition_set, obj.hit_sound, index, volume, custom_filename, when);\n }\n\n private get_timing_point(time: number): any {\n const points = this.resources?.beatmap.timing_points ?? [];\n for (let i = points.length - 1; i >= 0; i--) {\n if (points[i].time <= time) return points[i];\n }\n return points[0]; // fallback\n }\n\n private stop_render_loop(): void {\n if (this.animation_frame !== null) {\n cancelAnimationFrame(this.animation_frame);\n this.animation_frame = null;\n }\n }\n\n private render_frame(time: number): void {\n this.backend.clear();\n this.renderer?.render(time);\n\n // fps tracking\n if (this.enable_fps_counter) {\n this.fps_frame_count++;\n const now = performance.now();\n const delta = now - this.fps_last_update;\n\n if (delta >= 1000) {\n this.current_fps = Math.round((this.fps_frame_count * 1000) / delta);\n this.fps_frame_count = 0;\n this.fps_last_update = now;\n }\n\n this.backend.draw_text(`${this.current_fps} FPS`, 10, 20, \"14px monospace\", \"rgba(255,255,255,0.8)\", \"left\", \"top\");\n }\n }\n\n set_fps_counter(enabled: boolean): void {\n this.enable_fps_counter = enabled;\n }\n}\n"
|
|
28
33
|
],
|
|
29
|
-
"mappings": "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",
|
|
30
|
-
"debugId": "
|
|
34
|
+
"mappings": "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",
|
|
35
|
+
"debugId": "8D68191BE9969DD864756E2164756E21",
|
|
31
36
|
"names": []
|
|
32
37
|
}
|