Files
2nd/10_Wiki/Topics/Domain_Programming/Architecture/Beat_Saber.md
T
Antigravity Agent c24165b8bc refactor(topics): 멀티 에이전트용 지식 재편 — _Common(공통 기본기) + Domain_* 구조
에이전트 8종(대화형/프로그래머 C·S/디자이너/설계자/기획자/QA/PD/PM)에게
[공통 기본 능력 + 롤별 Specialty] 2층으로 지식을 주입하기 위한 재분류.
문서 내용·포맷은 무수정, 폴더 이동만 (6,372개 문서 수 보존 확인).

- Topic_Programming → Domain_Programming (내부 구조 보존)
- Topic_Graphic → Domain_Design
- Topic_Business → Domain_Product
- Topic_General → Domain_General
- _Common 신설: Math(구 Topic_Math_Specialty), Reasoning(구 General/From_Thinking & Reasoning),
  Reasoning_Creativity(구 General/From_창의성), Communication(Poetic_Blog_Writing + From_writing)
- 타 도메인의 From_* 폴더는 유지 (출처 표기일 뿐, 이미 도메인에 맞게 분류된 문서)
- 빈 폴더 정리 (memory/procedures)
- 에이전트→폴더 매핑은 workspace의 .astra/agent-knowledge-map.json (9개 에이전트)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 11:05:56 +09:00

5.6 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-beat-saber Beat Saber 10_Wiki/Topics verified self
Beat Saber
VR Rhythm Game
none A 0.85 applied
vr
game-architecture
rhythm-game
unity
ecs
2026-05-10 pending
language framework
csharp unity,unity-dots,openxr

Beat Saber

매 한 줄

"매 VR rhythm game 의 architecture 의 reference — 90Hz minimum framerate · sub-20ms motion-to-photon · ECS-style note pool". 2018 Beat Games (Meta acq 2019) release, 2026 의 Quest 3/Vision Pro 의 cross-platform mainstream, "framerate 의 holy 의 above 의 nothing" 의 architecture 의 lesson.

매 핵심

매 architecture 제약

  • Framerate floor: 90 fps (Quest 2) · 120 fps (Quest 3 · Vision Pro).
  • Motion-to-photon: < 20 ms.
  • GC 의 hostile: 매 frame 의 spike 의 nausea 의 cause → object pool · Burst · Job System.
  • Determinism: scoring 의 reproducible — 매 input · note 의 fixed seed.

매 component

  • Beatmap loader: .dat JSON parse → preallocated note buffer.
  • Note spawner: 매 future 6 sec 의 lookahead, pool 에서 의 pull.
  • Saber controller: hand pose tracking + velocity smoothing.
  • Cut detector: plane intersection · direction match · score.
  • Audio sync: NJS (Note Jump Speed) + offset 의 calibrate.

매 응용

  1. 매 fitness app (Supernatural, FitXR) 의 rhythm pattern 의 inherit.
  2. Trainer/simulator (medical · drill) 의 timing-critical UX.
  3. Education app (language drill · typing tutor) 의 VR variant.

💻 패턴

Unity DOTS: note spawn 의 zero-alloc

[BurstCompile]
public partial struct NoteSpawnSystem : ISystem
{
    public void OnUpdate(ref SystemState state)
    {
        var beatmap = SystemAPI.GetSingleton<BeatmapBuffer>();
        var time = SystemAPI.Time.ElapsedTime;
        var ecb = new EntityCommandBuffer(Allocator.Temp);

        for (int i = beatmap.NextIndex; i < beatmap.Notes.Length; i++)
        {
            var n = beatmap.Notes[i];
            if (n.Time - time > LookaheadSeconds) break;

            var e = ecb.Instantiate(beatmap.NotePrefab);
            ecb.SetComponent(e, new Translation { Value = n.SpawnPosition });
            ecb.SetComponent(e, new NoteData { CutDirection = n.Direction, HitTime = n.Time });
            beatmap.NextIndex = i + 1;
        }

        ecb.Playback(state.EntityManager);
    }
}

Saber-cut detector (plane intersection)

public bool TryCut(Vector3 saberTip, Vector3 saberBase, Vector3 saberVelocity, NoteData note,
                  out CutResult result)
{
    var plane = new Plane(saberVelocity.normalized, saberBase);
    if (!plane.Raycast(new Ray(note.Position, note.Forward), out float enter)) {
        result = default; return false;
    }

    float speed     = saberVelocity.magnitude;
    float angle     = Vector3.Angle(saberVelocity, note.RequiredCutDirection);
    float accuracy  = 1f - Mathf.Clamp01(angle / 60f);

    result = new CutResult {
        Score = Mathf.RoundToInt(speed * accuracy * 115f),
        IsValid = speed > 2f && angle < 60f,
    };
    return result.IsValid;
}

Audio-visual sync (NJS-based)

// Note 의 spawn position 의 calc
float jumpDist = njs * (60f / bpm) * halfJumpDuration * 2f;
Vector3 spawnPos = playerPosition + Vector3.forward * jumpDist;

// Note 의 frame 마다 의 lerp
float t = (Time.timeAsDouble - spawnTime) / (hitTime - spawnTime);
note.transform.position = Vector3.Lerp(spawnPos, hitPos, (float)t);

Object pool (zero-GC frame)

public class NotePool
{
    readonly Stack<Note> pool = new(256);
    readonly Note prefab;

    public Note Get() => pool.Count > 0 ? pool.Pop() : Object.Instantiate(prefab);
    public void Return(Note n) {
        n.gameObject.SetActive(false);
        pool.Push(n);
    }
}

OpenXR foveated rendering hint (Quest 3)

var feature = OpenXRSettings.Instance.GetFeature<FoveationFeature>();
feature.foveatedRenderingLevel = FoveatedRenderingLevel.High;
feature.useDynamicFoveatedRendering = true; // eye-tracked on Quest 3

매 결정 기준

상황 Approach
< 100 active note · prototype MonoBehaviour + pool
> 200 active note · production DOTS/ECS + Burst
Cross-platform (PCVR + Quest) Unity URP + multi-quality preset
Modding support Open beatmap format (.dat) + PluginLoader
매 90fps 미달 의 perf budget Foveation · LOD · GPU instancing

기본값: Unity DOTS + URP + OpenXR — 매 Quest 3 의 baseline 의 fit.

🔗 Graph

🤖 LLM 활용

언제: beatmap 의 procedural generation, cut-direction pattern 의 difficulty curve 의 tune, NJS · offset 의 starter value 의 suggest. 언제 X: 매 hand-crafted choreography (top mapper 의 art form) — LLM 의 generate 의 bland.

안티패턴

  • GC 의 frame 의 allocate: 매 90fps 의 break → motion sickness.
  • Animation curve 의 audio sync: dt 의 drift → pop. NJS-based linear lerp 의 use.
  • Saber 의 trigger collider: physics step 의 sub-frame miss — manual raycast/plane 의 use.
  • Per-note GameObject Instantiate: pool 의 mandatory.

🧪 검증 / 중복

  • Verified (Beat Games postmortem GDC 2019, Unity DOTS 1.3 docs, OpenXR 1.1 spec, BSMG modding wiki).
  • 신뢰도 A-.

🕓 Changelog

날짜 변경
2026-05-08 Phase 1
2026-05-10 Manual cleanup — VR architecture constraints + DOTS spawner + cut detector