diff --git a/.changeset/player-long-note-and-ruleset-signals.md b/.changeset/player-long-note-and-ruleset-signals.md new file mode 100644 index 000000000..3364f2458 --- /dev/null +++ b/.changeset/player-long-note-and-ruleset-signals.md @@ -0,0 +1,8 @@ +--- +'@be-music/player': minor +--- + +The engine now tells UI runtimes about long-note holds and about the ruleset a play is judged under, so a renderer no longer has to guess them from lane presses or re-derive the judge windows. + +- `PlayerUiCommand` gains `long-note-start` (channel, head beat, and the `ln` / `cn` / `hcn` mode the active ruleset actually plays the note in) and `long-note-end` (channel and a `complete` / `dropped` outcome). They are pushed in autoplay, auto-scratch, and manual play, next to the existing `hold-lane-until-beat` / `release-lane` pair. +- `PlayerOptions.onRulesetResolved` is called once before playback with a `PlayerRulesetInfo`: the ruleset id, its long-note style, and its judge window tables in µs, after the judge ruleset, the debug window override, and a replay's recorded settings were applied. Under LR2 the tables are the ones in force at the start of the chart; a later `#EXRANKxx` change is not reported. diff --git a/.changeset/player-web-skin-frame-data.md b/.changeset/player-web-skin-frame-data.md new file mode 100644 index 000000000..61b9e4cd3 --- /dev/null +++ b/.changeset/player-web-skin-frame-data.md @@ -0,0 +1,19 @@ +--- +'@be-music/player-web': minor +--- + +Be-music skins can change play options and open the readme from the select screen through the new `setPlayOption`, `cyclePlayOption`, and `toggleReadme` actions (unknown keys and values outside an option's choices are ignored, `hiSpeed` and `shutter` are clamped, and each change bumps the select frame's `revision`). `PixiPlayOptions` and its value unions are now aliases of the SDK's `BeMusicPlayOptions` types. + +The player now fills these new skin fields: + +- Runtime: `song`, `lastJudgeDeltaMs` / `judgeTimings`, `minBpm` / `maxBpm` / `mainBpm`, `songLengthMs` / `songElapsedMs`, `failedAtMs` / `allNotesDoneAtMs` / `outroAtMs`, `gaugeRiseAtMs` / `gaugeMaxAtMs`, `scoreHistory` / `gaugeHistory`, `laneCovers` / `visibleMs` / `greenNumber` (beatoraja's duration and green number, over the current scroll and BPM), and `judgeWindows` (the engine's resolved windows in ms; a mid-chart `#EXRANK` change is not reflected). +- Lanes and notes: each lane's `pressedAtMs` / `releasedAtMs` and `holding` / `holdStartedAtMs`, each long note's `mode` (as the active ruleset plays it) and `state` (`pending` / `held` / `dropped` / `done`), `autoplay` on notes and long notes played by autoplay or auto-scratch, the `judge` that set off each bomb, and `measureLines` (one per lane run) for skins that set `drawsMeasureLines`. +- Select: `pointer` in the stage's design pixels, `hit` returns whether the pointer is over the rect, and `songRecord(song)` answers from the new `resolveSongRecord` select-scene option, through which a host hands skins its per-chart best records (lamp, EX score, max combo, miss count, play count); without it every song reads as never played. +- Result data: `lamp`, `gaugeType`, `judgeRuleset`, `fast` / `slow`, and `judgeTimings`. +- Song images: `songImage(song, kind)` on the select, decide, gameplay, and result frames returns the song's `#STAGEFILE`, `#BANNER`, or `#BACKBMP` as an `ImageBitmap`, loaded lazily from the song collection (select bumps `revision` when one arrives). Each scene keeps at most 32 decoded images and closes the least recently used one beyond that. +- Skin settings: every frame carries `settings`. The gameplay, select, result, and decide scenes take the player's stored values through the new `beMusicSkinSettings` option, check them with `resolveBeMusicSkinSettings` (now also exported from `@be-music/player-web/skin`), and take changes through `setBeMusicSkinSettings`, which the skin sees from the next frame (select also bumps `revision`). Without stored values the skin draws with its defaults. +- BGA: a skin that sets `drawsBga` receives `frame.bga` with the active base, layer, and POOR images and `poorActive`. + +A skin that sets `drawsLaneCover`, `drawsMeasureLines`, or `drawsBga` now draws the lane covers, measure lines, or BGA itself, and the player stops drawing its own. + +The new `DefaultPixiDecideView` shows a skin's `decide` screen between select and play for its `durationMs` (Enter, Space, or a click skips ahead; Escape cancels back to select); hosts mount it only when the skin declares one. diff --git a/.changeset/skin-sdk-complete-frames.md b/.changeset/skin-sdk-complete-frames.md new file mode 100644 index 000000000..0a18b2ccc --- /dev/null +++ b/.changeset/skin-sdk-complete-frames.md @@ -0,0 +1,11 @@ +--- +'@be-music/skin-sdk': minor +--- + +Skins now receive everything they need to match what LR2 and beatoraja skins can show. Every addition is optional or opt-in, so existing skins keep working unchanged. + +- Gameplay runtime: `song`, `lastJudgeDeltaMs` / `judgeTimings` (positive = late), `judgeWindows`, `laneCovers`, `visibleMs`, `greenNumber`, `minBpm` / `maxBpm` / `mainBpm`, `songLengthMs` / `songElapsedMs`, `failedAtMs` / `allNotesDoneAtMs` / `outroAtMs`, `gaugeRiseAtMs` / `gaugeMaxAtMs`, and `scoreHistory` / `gaugeHistory`. +- Gameplay frame: `measureLines` and `bga` behind the new opt-in `drawsMeasureLines` / `drawsBga` flags, `drawsLaneCover`, per-lane press / release / hold times, long-note `mode` / `state`, `autoplay` on notes, and the `judge` behind each bomb. +- Select frame: `playOptions` / `playOptionChoices` with `setPlayOption`, `cyclePlayOption`, and `toggleReadme` actions, `pointer`, `songRecord(song)`, and `hit` returning whether the pointer is over the rect. `BeMusicPlayOptions` and its value unions now live in the SDK. +- Result data: `lamp`, `gaugeType`, `judgeRuleset`, `fast` / `slow`, and `judgeTimings`, with `binJudgeTimings` for timing histograms. +- An optional decide screen (`skin.decide`), skin settings (`skin.settings`, resolved with `resolveBeMusicSkinSettings` and checked by `validateBeMusicSkin`), and `songImage(song, kind)` on every frame. diff --git a/docs/be-music-skin.ja.md b/docs/be-music-skin.ja.md index 4896ad8fd..7822fd970 100644 --- a/docs/be-music-skin.ja.md +++ b/docs/be-music-skin.ja.md @@ -149,6 +149,8 @@ export default defineBeMusicSkin({ | `contextAttributes`、`setup`、`teardown` | — | [サーフェス](#サーフェス)と[フレームワークを使う](#フレームワークを使う)を参照。 | | `stage` | — | デザインキャンバス。既定は `wideStage`。[ステージとレイアウト](#ステージとレイアウト)を参照。 | | `gameplay`、`select`、`result` | ○ | 各画面の `draw` 関数。[画面](#画面)を参照。 | +| `decide` | — | 選曲とプレイの間の決定画面。[決定画面](#決定画面)を参照。 | +| `settings` | — | プレイヤーが調整できるスキンのオプション。[スキン設定](#スキン設定)を参照。 | `validateBeMusicSkin(skin)` は、例外を投げずに同じ問題をメッセージの配列で返します。 @@ -172,17 +174,31 @@ export default defineBeMusicSkin({ `gameplay.draw(surface, frame)` は `BeMusicGameplayFrame` を受け取ります。 - `layout`: [ステージとレイアウト](#ステージとレイアウト)を参照。 -- `lanes`: 各レーンの矩形(`x`、`w`、`top`、判定ライン位置の `bottom`)、`kind`、`beam`(キービーム強度。押下中は 1、離すと減衰)。 -- `notes`: タップノーツ `{ kind, x, w, y }`。`y` はノーツの下端です。 -- `longNotes`: ロングノーツ `{ kind, x, w, top, bottom }`。`top` が終端、`bottom` が始端で、押下中は判定ラインに張り付きます。 +- `lanes`: 各レーンの矩形(`x`、`w`、`top`、判定ライン位置の `bottom`)、`kind`、`beam`(キービーム強度。押下中は 1、離すと減衰)。`pressedAtMs` / `releasedAtMs` はそのレーンを最後に押した・離したプレイクロック時刻、`holding` と `holdStartedAtMs` はそのレーンでロングノーツを押し続けているかと、その開始時刻です。 +- `notes`: タップノーツ `{ kind, x, w, y }`。`y` はノーツの下端です。オートプレイやオートスクラッチが叩くノーツには `autoplay` が付きます。 +- `longNotes`: ロングノーツ `{ kind, x, w, top, bottom }`。`top` が終端、`bottom` が始端で、押下中は判定ラインに張り付きます。`mode`(`'ln'` / `'cn'` / `'hcn'`)は判定方式、`state`(`'pending'` / `'held'` / `'dropped'` / `'done'`)は進行状態、`autoplay` はオートプレイが処理するかを表します。 - `mines`: 地雷ノーツ `{ kind, x, w, y }`。`y` は下端です。判定ラインを通過する瞬間にそのレーンを押すと BAD になります。スキンが `gameplay.drawsMines`(後述)を設定したときだけ中身が入ります。 -- `bombs`: 生きているヒットエフェクト。`elapsedMs` と固定の `seed` を持ちます。 +- `bombs`: 生きているヒットエフェクト。`elapsedMs`、固定の `seed`、発生させた判定 `judge` を持ちます。 +- `measureLines`: 小節線 `{ side, x, w, y }`。横切るレーンランごとに 1 本です。スキンが `gameplay.drawsMeasureLines` を設定したときだけ中身が入ります。 +- `bga`: 合成する BGA のレイヤー(`{ base?, layer?, poor?, poorActive }`)。スキンが `gameplay.drawsBga` を設定したとき以外は `undefined` です。 - `runtime`: HUD の値(下記)。 - `beatPhase`、`nowMs`、`effects`、`audio`。 +- `settings` と `songImage`: [スキン設定](#スキン設定)と[曲の画像](#曲の画像)を参照。 `gameplay.bombDurationMs`(既定 300)でヒットエフェクトの寿命を指定します。 -`gameplay.drawsMines: true` を設定すると、地雷ノーツを `frame.mines` から自分で描けます。設定しない場合はプレイヤーが黄色の注意縞が入った赤いバーとしてキャンバスの上に描くので、地雷を扱わないスキンでも地雷は表示されます。 +#### 自分で描く + +既定では、いくつかの要素をプレイヤーがキャンバスの上(または後ろ)に描くので、それらを扱わないスキンでも表示されます。自分で描きたい場合は `gameplay` に対応するフラグを設定します。 + +| フラグ | 描画に使うデータ | 設定しない場合 | +| ------------------- | -------------------- | ---------------------------------------------------------------------- | +| `drawsMines` | `frame.mines` | プレイヤーが黄色の注意縞入りの赤いバーをキャンバスの上に描きます。 | +| `drawsLaneCover` | `runtime.laneCovers` | プレイヤーが SUDDEN+ / HIDDEN+ のカバーをキャンバスの上に描きます。 | +| `drawsMeasureLines` | `frame.measureLines` | プレイヤーが自前の小節線を描きます。 | +| `drawsBga` | `frame.bga` | プレイヤーが BGA をキャンバスの後ろ、`layout.bga` の位置に表示します。 | + +どのフラグも既定は `false` で、解禁されるフレームのフィールドは設定するまで空(または `undefined`)のままです。既存のスキンの見た目は変わりません。`drawsBga` では、`layer` の画像は BMS のレイヤーの慣習どおり純粋な黒が透明になった状態で渡され、`base` と `poor` は不透明です。通常のアルファブレンドで描き、`poorActive` の間は他の代わりに `poor` を表示してください。bmson のレイヤー(仕様で黒は不透明のまま)と動画のレイヤーは作者が作ったとおりに渡されます。画像は `ImageBitmap`、動画の BGA なら再生中の `