// 종족별 ASCII 캐릭터 프레임 데이터
// 모든 캐릭터는 3줄 × 6자 폭으로 통일 (보스 10줄과 대비)

import 'package:asciineverdie/src/shared/animation/character_frames.dart';

/// 종족별 캐릭터 프레임 저장소
class RaceCharacterFrames {
  RaceCharacterFrames._();

  /// 종족 ID로 프레임 데이터 조회
  static RaceFrameData? get(String raceId) => _raceFrames[raceId];

  /// 기본 프레임 (종족 미지정 시)
  static RaceFrameData get defaultFrames => _raceFrames['byte_human']!;

  /// 모든 종족 ID 목록
  static List<String> get allRaceIds => _raceFrames.keys.toList();
}

/// 종족별 프레임 데이터
class RaceFrameData {
  const RaceFrameData({
    required this.raceId,
    required this.idle,
    required this.prepare,
    required this.attack,
    required this.hit,
    required this.recover,
  });

  final String raceId;
  final List<CharacterFrame> idle; // 4 프레임
  final List<CharacterFrame> prepare; // 3 프레임
  final List<CharacterFrame> attack; // 5 프레임
  final List<CharacterFrame> hit; // 3 프레임
  final List<CharacterFrame> recover; // 3 프레임

  /// BattlePhase로 프레임 목록 조회
  List<CharacterFrame> getFrames(BattlePhase phase) {
    return switch (phase) {
      BattlePhase.idle => idle,
      BattlePhase.prepare => prepare,
      BattlePhase.attack => attack,
      BattlePhase.hit => hit,
      BattlePhase.recover => recover,
    };
  }
}

// ============================================================================
// 종족별 프레임 데이터 (21개 종족)
// 구조: [머리, 몸통+팔, 다리] - 모두 6자 폭
// ============================================================================

const _raceFrames = <String, RaceFrameData>{
  // --------------------------------------------------------------------------
  // 기본형 (Byte Human, Buffer Dwarf)
  // --------------------------------------------------------------------------
  'byte_human': RaceFrameData(
    raceId: 'byte_human',
    idle: [
      CharacterFrame([r'  o   ', r' /|\  ', r' / \  ']),
      CharacterFrame([r'  o   ', r' /|\  ', r' | |  ']),
      CharacterFrame([r'  o   ', r' /|\  ', r' / \  ']),
      CharacterFrame([r'  O   ', r' /|\  ', r' / \  ']),
    ],
    prepare: [
      CharacterFrame([r'  o   ', r' \|\  ', r' / \  ']),
      CharacterFrame([r'  o   ', r' \|   ', r' / \  ']),
      CharacterFrame([r'  o   ', r' \|/  ', r' / \  ']),
    ],
    attack: [
      CharacterFrame([r'  o   ', r' \|   ', r' / \  ']),
      CharacterFrame([r'  o   ', r' \|-  ', r' / \  ']),
      CharacterFrame([r'  o   ', r' \|-- ', r' / \  ']),
      CharacterFrame([r'  o   ', r'\|-=> ', r' / \  ']),
      CharacterFrame([r'  o   ', r' /|\  ', r' / \  ']),
    ],
    hit: [
      CharacterFrame([r'  o   ', r'/|\*  ', r' / \  ']),
      CharacterFrame([r'  o   ', r'/|\ * ', r' / \  ']),
      CharacterFrame([r'  o   ', r' /|\  ', r' / \  ']),
    ],
    recover: [
      CharacterFrame([r'  o   ', r' /|\  ', r'  |   ']),
      CharacterFrame([r'  o   ', r' /|\  ', r' / \  ']),
      CharacterFrame([r'  o   ', r' /|\  ', r' / \  ']),
    ],
  ),

  'buffer_dwarf': RaceFrameData(
    raceId: 'buffer_dwarf',
    idle: [
      CharacterFrame([r'  o   ', r' /█\  ', r' / \  ']),
      CharacterFrame([r'  o   ', r' /█\  ', r' | |  ']),
      CharacterFrame([r'  o   ', r' /█\  ', r' / \  ']),
      CharacterFrame([r'  O   ', r' /█\  ', r' / \  ']),
    ],
    prepare: [
      CharacterFrame([r'  o   ', r' \█\  ', r' / \  ']),
      CharacterFrame([r'  o   ', r' \█   ', r' / \  ']),
      CharacterFrame([r'  o   ', r' \█/  ', r' / \  ']),
    ],
    attack: [
      CharacterFrame([r'  o   ', r' \█   ', r' / \  ']),
      CharacterFrame([r'  o   ', r' \█-  ', r' / \  ']),
      CharacterFrame([r'  o   ', r' \█-- ', r' / \  ']),
      CharacterFrame([r'  o   ', r'\█-=> ', r' / \  ']),
      CharacterFrame([r'  o   ', r' /█\  ', r' / \  ']),
    ],
    hit: [
      CharacterFrame([r'  o   ', r'/█\*  ', r' / \  ']),
      CharacterFrame([r'  o   ', r'/█\ * ', r' / \  ']),
      CharacterFrame([r'  o   ', r' /█\  ', r' / \  ']),
    ],
    recover: [
      CharacterFrame([r'  o   ', r' /█\  ', r'  |   ']),
      CharacterFrame([r'  o   ', r' /█\  ', r' / \  ']),
      CharacterFrame([r'  o   ', r' /█\  ', r' / \  ']),
    ],
  ),

  // --------------------------------------------------------------------------
  // 대형 (Kernel Giant, Heap Troll)
  // --------------------------------------------------------------------------
  'kernel_giant': RaceFrameData(
    raceId: 'kernel_giant',
    idle: [
      CharacterFrame([r'  O   ', r' /█\  ', r' ┘ └  ']),
      CharacterFrame([r'  O   ', r' /█\  ', r' |  | ']),
      CharacterFrame([r'  O   ', r' /█\  ', r' ┘ └  ']),
      CharacterFrame([r'  O   ', r' /█\  ', r' ┘ └  ']),
    ],
    prepare: [
      CharacterFrame([r'  O   ', r' \█\  ', r' ┘ └  ']),
      CharacterFrame([r'  O   ', r' \█   ', r' ┘ └  ']),
      CharacterFrame([r'  O   ', r' \█/  ', r' ┘ └  ']),
    ],
    attack: [
      CharacterFrame([r'  O   ', r' \█   ', r' ┘ └  ']),
      CharacterFrame([r'  O   ', r' \█-  ', r' ┘ └  ']),
      CharacterFrame([r'  O   ', r' \█-- ', r' ┘ └  ']),
      CharacterFrame([r'  O   ', r'\█-=> ', r' ┘ └  ']),
      CharacterFrame([r'  O   ', r' /█\  ', r' ┘ └  ']),
    ],
    hit: [
      CharacterFrame([r'  O   ', r'/█\*  ', r' ┘ └  ']),
      CharacterFrame([r'  O   ', r'/█\ * ', r' ┘ └  ']),
      CharacterFrame([r'  O   ', r' /█\  ', r' ┘ └  ']),
    ],
    recover: [
      CharacterFrame([r'  O   ', r' /█\  ', r'  ||  ']),
      CharacterFrame([r'  O   ', r' /█\  ', r' ┘ └  ']),
      CharacterFrame([r'  O   ', r' /█\  ', r' ┘ └  ']),
    ],
  ),

  'heap_troll': RaceFrameData(
    raceId: 'heap_troll',
    idle: [
      CharacterFrame([r'  Ö   ', r' /▓\  ', r' ┘ └  ']),
      CharacterFrame([r'  Ö   ', r' /▓\  ', r' | |  ']),
      CharacterFrame([r'  Ö   ', r' /▓\  ', r' ┘ └  ']),
      CharacterFrame([r'  Ö   ', r' /▓\  ', r' ┘ └  ']),
    ],
    prepare: [
      CharacterFrame([r'  Ö   ', r' \▓\  ', r' ┘ └  ']),
      CharacterFrame([r'  Ö   ', r' \▓   ', r' ┘ └  ']),
      CharacterFrame([r'  Ö   ', r' \▓/  ', r' ┘ └  ']),
    ],
    attack: [
      CharacterFrame([r'  Ö   ', r' \▓   ', r' ┘ └  ']),
      CharacterFrame([r'  Ö   ', r' \▓-  ', r' ┘ └  ']),
      CharacterFrame([r'  Ö   ', r' \▓-- ', r' ┘ └  ']),
      CharacterFrame([r'  Ö   ', r'\▓-=> ', r' ┘ └  ']),
      CharacterFrame([r'  Ö   ', r' /▓\  ', r' ┘ └  ']),
    ],
    hit: [
      CharacterFrame([r'  Ö   ', r'/▓\*  ', r' ┘ └  ']),
      CharacterFrame([r'  Ö   ', r'/▓\ * ', r' ┘ └  ']),
      CharacterFrame([r'  Ö   ', r' /▓\  ', r' ┘ └  ']),
    ],
    recover: [
      CharacterFrame([r'  Ö   ', r' /▓\  ', r'  ||  ']),
      CharacterFrame([r'  Ö   ', r' /▓\  ', r' ┘ └  ']),
      CharacterFrame([r'  Ö   ', r' /▓\  ', r' ┘ └  ']),
    ],
  ),

  // --------------------------------------------------------------------------
  // 전사형 (Protocol Valkyrie, Flag Golem, Array Orc)
  // --------------------------------------------------------------------------
  'protocol_valkyrie': RaceFrameData(
    raceId: 'protocol_valkyrie',
    idle: [
      CharacterFrame([r'  o   ', r' /|+  ', r' / \  ']),
      CharacterFrame([r'  o   ', r' /|+  ', r' | |  ']),
      CharacterFrame([r'  o   ', r' /|+  ', r' / \  ']),
      CharacterFrame([r'  O   ', r' /|+  ', r' / \  ']),
    ],
    prepare: [
      CharacterFrame([r'  o   ', r' \|+  ', r' / \  ']),
      CharacterFrame([r'  o   ', r' \|   ', r' / \  ']),
      CharacterFrame([r'  o   ', r' \|/  ', r' / \  ']),
    ],
    attack: [
      CharacterFrame([r'  o   ', r' \|   ', r' / \  ']),
      CharacterFrame([r'  o   ', r' \|-  ', r' / \  ']),
      CharacterFrame([r'  o   ', r' \|-- ', r' / \  ']),
      CharacterFrame([r'  o   ', r'\|-+> ', r' / \  ']),
      CharacterFrame([r'  o   ', r' /|+  ', r' / \  ']),
    ],
    hit: [
      CharacterFrame([r'  o   ', r'/|+*  ', r' / \  ']),
      CharacterFrame([r'  o   ', r'/|+ * ', r' / \  ']),
      CharacterFrame([r'  o   ', r' /|+  ', r' / \  ']),
    ],
    recover: [
      CharacterFrame([r'  o   ', r' /|+  ', r'  |   ']),
      CharacterFrame([r'  o   ', r' /|+  ', r' / \  ']),
      CharacterFrame([r'  o   ', r' /|+  ', r' / \  ']),
    ],
  ),

  'flag_golem': RaceFrameData(
    raceId: 'flag_golem',
    idle: [
      CharacterFrame([r'  ♦   ', r' /|]  ', r' / \  ']),
      CharacterFrame([r'  ♦   ', r' /|]  ', r' | |  ']),
      CharacterFrame([r'  ♦   ', r' /|]  ', r' / \  ']),
      CharacterFrame([r'  ◆   ', r' /|]  ', r' / \  ']),
    ],
    prepare: [
      CharacterFrame([r'  ♦   ', r' \|]  ', r' / \  ']),
      CharacterFrame([r'  ♦   ', r' \|   ', r' / \  ']),
      CharacterFrame([r'  ♦   ', r' \|/  ', r' / \  ']),
    ],
    attack: [
      CharacterFrame([r'  ♦   ', r' \|   ', r' / \  ']),
      CharacterFrame([r'  ♦   ', r' \|-  ', r' / \  ']),
      CharacterFrame([r'  ♦   ', r' \|-- ', r' / \  ']),
      CharacterFrame([r'  ♦   ', r'\|--> ', r' / \  ']),
      CharacterFrame([r'  ♦   ', r' /|]  ', r' / \  ']),
    ],
    hit: [
      CharacterFrame([r'  ♦   ', r'/|]*  ', r' / \  ']),
      CharacterFrame([r'  ♦   ', r'/|] * ', r' / \  ']),
      CharacterFrame([r'  ♦   ', r' /|]  ', r' / \  ']),
    ],
    recover: [
      CharacterFrame([r'  ♦   ', r' /|]  ', r'  |   ']),
      CharacterFrame([r'  ♦   ', r' /|]  ', r' / \  ']),
      CharacterFrame([r'  ♦   ', r' /|]  ', r' / \  ']),
    ],
  ),

  'array_orc': RaceFrameData(
    raceId: 'array_orc',
    idle: [
      CharacterFrame([r'  ö   ', r' /▒\  ', r' / \  ']),
      CharacterFrame([r'  ö   ', r' /▒\  ', r' | |  ']),
      CharacterFrame([r'  ö   ', r' /▒\  ', r' / \  ']),
      CharacterFrame([r'  Ö   ', r' /▒\  ', r' / \  ']),
    ],
    prepare: [
      CharacterFrame([r'  ö   ', r' \▒\  ', r' / \  ']),
      CharacterFrame([r'  ö   ', r' \▒   ', r' / \  ']),
      CharacterFrame([r'  ö   ', r' \▒/  ', r' / \  ']),
    ],
    attack: [
      CharacterFrame([r'  ö   ', r' \▒   ', r' / \  ']),
      CharacterFrame([r'  ö   ', r' \▒-  ', r' / \  ']),
      CharacterFrame([r'  ö   ', r' \▒-- ', r' / \  ']),
      CharacterFrame([r'  ö   ', r'\▒-=> ', r' / \  ']),
      CharacterFrame([r'  ö   ', r' /▒\  ', r' / \  ']),
    ],
    hit: [
      CharacterFrame([r'  ö   ', r'/▒\*  ', r' / \  ']),
      CharacterFrame([r'  ö   ', r'/▒\ * ', r' / \  ']),
      CharacterFrame([r'  ö   ', r' /▒\  ', r' / \  ']),
    ],
    recover: [
      CharacterFrame([r'  ö   ', r' /▒\  ', r'  |   ']),
      CharacterFrame([r'  ö   ', r' /▒\  ', r' / \  ']),
      CharacterFrame([r'  ö   ', r' /▒\  ', r' / \  ']),
    ],
  ),

  // --------------------------------------------------------------------------
  // 마법형 (Loop Djinn, Lambda Dryad, Recursive Sylvan)
  // --------------------------------------------------------------------------
  'loop_djinn': RaceFrameData(
    raceId: 'loop_djinn',
    idle: [
      CharacterFrame([r' o~   ', r' /|)  ', r' / \  ']),
      CharacterFrame([r' o~   ', r' /|)  ', r' | |  ']),
      CharacterFrame([r' o~   ', r' /|)  ', r' / \  ']),
      CharacterFrame([r' O~   ', r' /|)  ', r' / \  ']),
    ],
    prepare: [
      CharacterFrame([r' o~   ', r' \|)  ', r' / \  ']),
      CharacterFrame([r' o~   ', r' \|   ', r' / \  ']),
      CharacterFrame([r' o~   ', r' \|/  ', r' / \  ']),
    ],
    attack: [
      CharacterFrame([r' o~   ', r' \|   ', r' / \  ']),
      CharacterFrame([r' o~   ', r' \|~  ', r' / \  ']),
      CharacterFrame([r' o~   ', r' \|~~ ', r' / \  ']),
      CharacterFrame([r' o~   ', r'\|~~* ', r' / \  ']),
      CharacterFrame([r' o~   ', r' /|)  ', r' / \  ']),
    ],
    hit: [
      CharacterFrame([r' o~   ', r'/|)*  ', r' / \  ']),
      CharacterFrame([r' o~   ', r'/|) * ', r' / \  ']),
      CharacterFrame([r' o~   ', r' /|)  ', r' / \  ']),
    ],
    recover: [
      CharacterFrame([r' o~   ', r' /|)  ', r'  |   ']),
      CharacterFrame([r' o~   ', r' /|)  ', r' / \  ']),
      CharacterFrame([r' o~   ', r' /|)  ', r' / \  ']),
    ],
  ),

  'lambda_dryad': RaceFrameData(
    raceId: 'lambda_dryad',
    idle: [
      CharacterFrame([r' o♣   ', r' /|)  ', r' / \  ']),
      CharacterFrame([r' o♣   ', r' /|)  ', r' | |  ']),
      CharacterFrame([r' o♣   ', r' /|)  ', r' / \  ']),
      CharacterFrame([r' O♣   ', r' /|)  ', r' / \  ']),
    ],
    prepare: [
      CharacterFrame([r' o♣   ', r' \|)  ', r' / \  ']),
      CharacterFrame([r' o♣   ', r' \|   ', r' / \  ']),
      CharacterFrame([r' o♣   ', r' \|/  ', r' / \  ']),
    ],
    attack: [
      CharacterFrame([r' o♣   ', r' \|   ', r' / \  ']),
      CharacterFrame([r' o♣   ', r' \|~  ', r' / \  ']),
      CharacterFrame([r' o♣   ', r' \|~~ ', r' / \  ']),
      CharacterFrame([r' o♣   ', r'\|~~♣ ', r' / \  ']),
      CharacterFrame([r' o♣   ', r' /|)  ', r' / \  ']),
    ],
    hit: [
      CharacterFrame([r' o♣   ', r'/|)*  ', r' / \  ']),
      CharacterFrame([r' o♣   ', r'/|) * ', r' / \  ']),
      CharacterFrame([r' o♣   ', r' /|)  ', r' / \  ']),
    ],
    recover: [
      CharacterFrame([r' o♣   ', r' /|)  ', r'  |   ']),
      CharacterFrame([r' o♣   ', r' /|)  ', r' / \  ']),
      CharacterFrame([r' o♣   ', r' /|)  ', r' / \  ']),
    ],
  ),

  'recursive_sylvan': RaceFrameData(
    raceId: 'recursive_sylvan',
    idle: [
      CharacterFrame([r' o∞   ', r' /|)  ', r' / \  ']),
      CharacterFrame([r' o∞   ', r' /|)  ', r' | |  ']),
      CharacterFrame([r' o∞   ', r' /|)  ', r' / \  ']),
      CharacterFrame([r' O∞   ', r' /|)  ', r' / \  ']),
    ],
    prepare: [
      CharacterFrame([r' o∞   ', r' \|)  ', r' / \  ']),
      CharacterFrame([r' o∞   ', r' \|   ', r' / \  ']),
      CharacterFrame([r' o∞   ', r' \|/  ', r' / \  ']),
    ],
    attack: [
      CharacterFrame([r' o∞   ', r' \|   ', r' / \  ']),
      CharacterFrame([r' o∞   ', r' \|~  ', r' / \  ']),
      CharacterFrame([r' o∞   ', r' \|~~ ', r' / \  ']),
      CharacterFrame([r' o∞   ', r'\|~~∞ ', r' / \  ']),
      CharacterFrame([r' o∞   ', r' /|)  ', r' / \  ']),
    ],
    hit: [
      CharacterFrame([r' o∞   ', r'/|)*  ', r' / \  ']),
      CharacterFrame([r' o∞   ', r'/|) * ', r' / \  ']),
      CharacterFrame([r' o∞   ', r' /|)  ', r' / \  ']),
    ],
    recover: [
      CharacterFrame([r' o∞   ', r' /|)  ', r'  |   ']),
      CharacterFrame([r' o∞   ', r' /|)  ', r' / \  ']),
      CharacterFrame([r' o∞   ', r' /|)  ', r' / \  ']),
    ],
  ),

  // --------------------------------------------------------------------------
  // 언데드/엘프 (Coredump Undead, Null Elf, Callback Seraph)
  // --------------------------------------------------------------------------
  'coredump_undead': RaceFrameData(
    raceId: 'coredump_undead',
    idle: [
      CharacterFrame([r'  ☠   ', r' /|\  ', r' / \  ']),
      CharacterFrame([r'  ☠   ', r' /|\  ', r' | |  ']),
      CharacterFrame([r'  ☠   ', r' /|\  ', r' / \  ']),
      CharacterFrame([r'  ☠   ', r' /|\  ', r' / \  ']),
    ],
    prepare: [
      CharacterFrame([r'  ☠   ', r' \|\  ', r' / \  ']),
      CharacterFrame([r'  ☠   ', r' \|   ', r' / \  ']),
      CharacterFrame([r'  ☠   ', r' \|/  ', r' / \  ']),
    ],
    attack: [
      CharacterFrame([r'  ☠   ', r' \|   ', r' / \  ']),
      CharacterFrame([r'  ☠   ', r' \|-  ', r' / \  ']),
      CharacterFrame([r'  ☠   ', r' \|-- ', r' / \  ']),
      CharacterFrame([r'  ☠   ', r'\|-~> ', r' / \  ']),
      CharacterFrame([r'  ☠   ', r' /|\  ', r' / \  ']),
    ],
    hit: [
      CharacterFrame([r'  ☠   ', r'/|\~  ', r' / \  ']),
      CharacterFrame([r'  ☠   ', r'/|\ ~ ', r' / \  ']),
      CharacterFrame([r'  ☠   ', r' /|\  ', r' / \  ']),
    ],
    recover: [
      CharacterFrame([r'  ☠   ', r' /|\  ', r'  |   ']),
      CharacterFrame([r'  ☠   ', r' /|\  ', r' / \  ']),
      CharacterFrame([r'  ☠   ', r' /|\  ', r' / \  ']),
    ],
  ),

  'null_elf': RaceFrameData(
    raceId: 'null_elf',
    idle: [
      CharacterFrame([r'  ö   ', r' /|\  ', r' / \  ']),
      CharacterFrame([r'  ö   ', r' /|\  ', r' | |  ']),
      CharacterFrame([r'  ö   ', r' /|\  ', r' / \  ']),
      CharacterFrame([r'  Ö   ', r' /|\  ', r' / \  ']),
    ],
    prepare: [
      CharacterFrame([r'  ö   ', r' \|\  ', r' / \  ']),
      CharacterFrame([r'  ö   ', r' \|   ', r' / \  ']),
      CharacterFrame([r'  ö   ', r' \|/  ', r' / \  ']),
    ],
    attack: [
      CharacterFrame([r'  ö   ', r' \|   ', r' / \  ']),
      CharacterFrame([r'  ö   ', r' \|~  ', r' / \  ']),
      CharacterFrame([r'  ö   ', r' \|~~ ', r' / \  ']),
      CharacterFrame([r'  ö   ', r'\|~~* ', r' / \  ']),
      CharacterFrame([r'  ö   ', r' /|\  ', r' / \  ']),
    ],
    hit: [
      CharacterFrame([r'  ö   ', r'/|\*  ', r' / \  ']),
      CharacterFrame([r'  ö   ', r'/|\ * ', r' / \  ']),
      CharacterFrame([r'  ö   ', r' /|\  ', r' / \  ']),
    ],
    recover: [
      CharacterFrame([r'  ö   ', r' /|\  ', r'  |   ']),
      CharacterFrame([r'  ö   ', r' /|\  ', r' / \  ']),
      CharacterFrame([r'  ö   ', r' /|\  ', r' / \  ']),
    ],
  ),

  'callback_seraph': RaceFrameData(
    raceId: 'callback_seraph',
    idle: [
      CharacterFrame([r'  ô   ', r' /|\  ', r' / \  ']),
      CharacterFrame([r'  ô   ', r' /|\  ', r' | |  ']),
      CharacterFrame([r'  ô   ', r' /|\  ', r' / \  ']),
      CharacterFrame([r'  Ô   ', r' /|\  ', r' / \  ']),
    ],
    prepare: [
      CharacterFrame([r'  ô   ', r' \|\  ', r' / \  ']),
      CharacterFrame([r'  ô   ', r' \|   ', r' / \  ']),
      CharacterFrame([r'  ô   ', r' \|/  ', r' / \  ']),
    ],
    attack: [
      CharacterFrame([r'  ô   ', r' \|   ', r' / \  ']),
      CharacterFrame([r'  ô   ', r' \|+  ', r' / \  ']),
      CharacterFrame([r'  ô   ', r' \|++ ', r' / \  ']),
      CharacterFrame([r'  ô   ', r'\|++* ', r' / \  ']),
      CharacterFrame([r'  ô   ', r' /|\  ', r' / \  ']),
    ],
    hit: [
      CharacterFrame([r'  ô   ', r'/|\+  ', r' / \  ']),
      CharacterFrame([r'  ô   ', r'/|\ + ', r' / \  ']),
      CharacterFrame([r'  ô   ', r' /|\  ', r' / \  ']),
    ],
    recover: [
      CharacterFrame([r'  ô   ', r' /|\  ', r'  |   ']),
      CharacterFrame([r'  ô   ', r' /|\  ', r' / \  ']),
      CharacterFrame([r'  ô   ', r' /|\  ', r' / \  ']),
    ],
  ),

  // --------------------------------------------------------------------------
  // 소형 (Bit Halfling, Stack Goblin, Cache Imp)
  // --------------------------------------------------------------------------
  'bit_halfling': RaceFrameData(
    raceId: 'bit_halfling',
    idle: [
      CharacterFrame([r'  o   ', r' /|\  ', r'  Y   ']),
      CharacterFrame([r'  o   ', r' /|\  ', r'  |   ']),
      CharacterFrame([r'  o   ', r' /|\  ', r'  Y   ']),
      CharacterFrame([r'  O   ', r' /|\  ', r'  Y   ']),
    ],
    prepare: [
      CharacterFrame([r'  o   ', r' \|\  ', r'  Y   ']),
      CharacterFrame([r'  o   ', r' \|   ', r'  Y   ']),
      CharacterFrame([r'  o   ', r' \|/  ', r'  Y   ']),
    ],
    attack: [
      CharacterFrame([r'  o   ', r' \|   ', r'  Y   ']),
      CharacterFrame([r'  o   ', r' \|-  ', r'  Y   ']),
      CharacterFrame([r'  o   ', r' \|-- ', r'  Y   ']),
      CharacterFrame([r'  o   ', r'\|-=> ', r'  Y   ']),
      CharacterFrame([r'  o   ', r' /|\  ', r'  Y   ']),
    ],
    hit: [
      CharacterFrame([r'  o   ', r'/|\*  ', r'  Y   ']),
      CharacterFrame([r'  o   ', r'/|\ * ', r'  Y   ']),
      CharacterFrame([r'  o   ', r' /|\  ', r'  Y   ']),
    ],
    recover: [
      CharacterFrame([r'  o   ', r' /|\  ', r'  |   ']),
      CharacterFrame([r'  o   ', r' /|\  ', r'  Y   ']),
      CharacterFrame([r'  o   ', r' /|\  ', r'  Y   ']),
    ],
  ),

  'stack_goblin': RaceFrameData(
    raceId: 'stack_goblin',
    idle: [
      CharacterFrame([r'  ◦   ', r' /|\  ', r'  Y   ']),
      CharacterFrame([r'  ◦   ', r' /|\  ', r'  |   ']),
      CharacterFrame([r'  ◦   ', r' /|\  ', r'  Y   ']),
      CharacterFrame([r'  ●   ', r' /|\  ', r'  Y   ']),
    ],
    prepare: [
      CharacterFrame([r'  ◦   ', r' \|\  ', r'  Y   ']),
      CharacterFrame([r'  ◦   ', r' \|   ', r'  Y   ']),
      CharacterFrame([r'  ◦   ', r' \|/  ', r'  Y   ']),
    ],
    attack: [
      CharacterFrame([r'  ◦   ', r' \|   ', r'  Y   ']),
      CharacterFrame([r'  ◦   ', r' \|-  ', r'  Y   ']),
      CharacterFrame([r'  ◦   ', r' \|-- ', r'  Y   ']),
      CharacterFrame([r'  ◦   ', r'\|-=> ', r'  Y   ']),
      CharacterFrame([r'  ◦   ', r' /|\  ', r'  Y   ']),
    ],
    hit: [
      CharacterFrame([r'  ◦   ', r'/|\*  ', r'  Y   ']),
      CharacterFrame([r'  ◦   ', r'/|\ * ', r'  Y   ']),
      CharacterFrame([r'  ◦   ', r' /|\  ', r'  Y   ']),
    ],
    recover: [
      CharacterFrame([r'  ◦   ', r' /|\  ', r'  |   ']),
      CharacterFrame([r'  ◦   ', r' /|\  ', r'  Y   ']),
      CharacterFrame([r'  ◦   ', r' /|\  ', r'  Y   ']),
    ],
  ),

  'cache_imp': RaceFrameData(
    raceId: 'cache_imp',
    idle: [
      CharacterFrame([r'  ^   ', r' /|\  ', r'  Y   ']),
      CharacterFrame([r'  ^   ', r' /|\  ', r'  |   ']),
      CharacterFrame([r'  ^   ', r' /|\  ', r'  Y   ']),
      CharacterFrame([r'  ^   ', r' /|\  ', r'  Y   ']),
    ],
    prepare: [
      CharacterFrame([r'  ^   ', r' \|\  ', r'  Y   ']),
      CharacterFrame([r'  ^   ', r' \|   ', r'  Y   ']),
      CharacterFrame([r'  ^   ', r' \|/  ', r'  Y   ']),
    ],
    attack: [
      CharacterFrame([r'  ^   ', r' \|   ', r'  Y   ']),
      CharacterFrame([r'  ^   ', r' \|-  ', r'  Y   ']),
      CharacterFrame([r'  ^   ', r' \|-- ', r'  Y   ']),
      CharacterFrame([r'  ^   ', r'\|--> ', r'  Y   ']),
      CharacterFrame([r'  ^   ', r' /|\  ', r'  Y   ']),
    ],
    hit: [
      CharacterFrame([r'  ^   ', r'/|\*  ', r'  Y   ']),
      CharacterFrame([r'  ^   ', r'/|\ * ', r'  Y   ']),
      CharacterFrame([r'  ^   ', r' /|\  ', r'  Y   ']),
    ],
    recover: [
      CharacterFrame([r'  ^   ', r' /|\  ', r'  |   ']),
      CharacterFrame([r'  ^   ', r' /|\  ', r'  Y   ']),
      CharacterFrame([r'  ^   ', r' /|\  ', r'  Y   ']),
    ],
  ),

  // --------------------------------------------------------------------------
  // 영체 (Thread Spirit, Pointer Fairy)
  // --------------------------------------------------------------------------
  'thread_spirit': RaceFrameData(
    raceId: 'thread_spirit',
    idle: [
      CharacterFrame([r' ·o·  ', r'  |   ', r' ~~~  ']),
      CharacterFrame([r' ·o·  ', r'  |   ', r' ~~   ']),
      CharacterFrame([r' ·o·  ', r'  |   ', r' ~~~  ']),
      CharacterFrame([r' ·O·  ', r'  |   ', r' ~~~  ']),
    ],
    prepare: [
      CharacterFrame([r' ·o·  ', r' \|   ', r' ~~~  ']),
      CharacterFrame([r' ·o·  ', r' \    ', r' ~~~  ']),
      CharacterFrame([r' ·o·  ', r' \/   ', r' ~~~  ']),
    ],
    attack: [
      CharacterFrame([r' ·o·  ', r' \    ', r' ~~~  ']),
      CharacterFrame([r' ·o·  ', r' \~   ', r' ~~~  ']),
      CharacterFrame([r' ·o·  ', r' \~~  ', r' ~~~  ']),
      CharacterFrame([r' ·o·  ', r'\~~*  ', r' ~~~  ']),
      CharacterFrame([r' ·o·  ', r'  |   ', r' ~~~  ']),
    ],
    hit: [
      CharacterFrame([r' ·o·  ', r' |*   ', r' ~~~  ']),
      CharacterFrame([r' ·o·  ', r' | *  ', r' ~~~  ']),
      CharacterFrame([r' ·o·  ', r'  |   ', r' ~~~  ']),
    ],
    recover: [
      CharacterFrame([r' ·o·  ', r'  |   ', r' ~~   ']),
      CharacterFrame([r' ·o·  ', r'  |   ', r' ~~~  ']),
      CharacterFrame([r' ·o·  ', r'  |   ', r' ~~~  ']),
    ],
  ),

  'pointer_fairy': RaceFrameData(
    raceId: 'pointer_fairy',
    idle: [
      CharacterFrame([r' *o*  ', r'  |   ', r' ~~~  ']),
      CharacterFrame([r' *o*  ', r'  |   ', r' ~~   ']),
      CharacterFrame([r' *o*  ', r'  |   ', r' ~~~  ']),
      CharacterFrame([r' *O*  ', r'  |   ', r' ~~~  ']),
    ],
    prepare: [
      CharacterFrame([r' *o*  ', r' \|   ', r' ~~~  ']),
      CharacterFrame([r' *o*  ', r' \    ', r' ~~~  ']),
      CharacterFrame([r' *o*  ', r' \/   ', r' ~~~  ']),
    ],
    attack: [
      CharacterFrame([r' *o*  ', r' \    ', r' ~~~  ']),
      CharacterFrame([r' *o*  ', r' \*   ', r' ~~~  ']),
      CharacterFrame([r' *o*  ', r' \**  ', r' ~~~  ']),
      CharacterFrame([r' *o*  ', r'\**+  ', r' ~~~  ']),
      CharacterFrame([r' *o*  ', r'  |   ', r' ~~~  ']),
    ],
    hit: [
      CharacterFrame([r' *o*  ', r' |+   ', r' ~~~  ']),
      CharacterFrame([r' *o*  ', r' | +  ', r' ~~~  ']),
      CharacterFrame([r' *o*  ', r'  |   ', r' ~~~  ']),
    ],
    recover: [
      CharacterFrame([r' *o*  ', r'  |   ', r' ~~   ']),
      CharacterFrame([r' *o*  ', r'  |   ', r' ~~~  ']),
      CharacterFrame([r' *o*  ', r'  |   ', r' ~~~  ']),
    ],
  ),

  // --------------------------------------------------------------------------
  // 민첩형 (Index Feline, Iterator Shade)
  // --------------------------------------------------------------------------
  'index_feline': RaceFrameData(
    raceId: 'index_feline',
    idle: [
      CharacterFrame([r'  o   ', r' /|\  ', r' λ \  ']),
      CharacterFrame([r'  o   ', r' /|\  ', r' | |  ']),
      CharacterFrame([r'  o   ', r' /|\  ', r' λ \  ']),
      CharacterFrame([r'  O   ', r' /|\  ', r' λ \  ']),
    ],
    prepare: [
      CharacterFrame([r'  o   ', r' \|\  ', r' λ \  ']),
      CharacterFrame([r'  o   ', r' \|   ', r' λ \  ']),
      CharacterFrame([r'  o   ', r' \|/  ', r' λ \  ']),
    ],
    attack: [
      CharacterFrame([r'  o   ', r' \|   ', r' λ \  ']),
      CharacterFrame([r'  o   ', r' \|)  ', r' λ \  ']),
      CharacterFrame([r'  o   ', r' \|)) ', r' λ \  ']),
      CharacterFrame([r'  o   ', r'\|))> ', r' λ \  ']),
      CharacterFrame([r'  o   ', r' /|\  ', r' λ \  ']),
    ],
    hit: [
      CharacterFrame([r'  o   ', r'/|\*  ', r' λ \  ']),
      CharacterFrame([r'  o   ', r'/|\ * ', r' λ \  ']),
      CharacterFrame([r'  o   ', r' /|\  ', r' λ \  ']),
    ],
    recover: [
      CharacterFrame([r'  o   ', r' /|\  ', r'  |   ']),
      CharacterFrame([r'  o   ', r' /|\  ', r' λ \  ']),
      CharacterFrame([r'  o   ', r' /|\  ', r' λ \  ']),
    ],
  ),

  'iterator_shade': RaceFrameData(
    raceId: 'iterator_shade',
    idle: [
      CharacterFrame([r'  o   ', r' /|\  ', r' λ \  ']),
      CharacterFrame([r'  o   ', r' /|\  ', r' | |  ']),
      CharacterFrame([r'  o   ', r' /|\  ', r' λ \  ']),
      CharacterFrame([r'  o   ', r' /|\  ', r' λ \  ']),
    ],
    prepare: [
      CharacterFrame([r'  o   ', r' \|\  ', r' λ \  ']),
      CharacterFrame([r'  o   ', r' \|   ', r' λ \  ']),
      CharacterFrame([r'  o   ', r' \|/  ', r' λ \  ']),
    ],
    attack: [
      CharacterFrame([r'  o   ', r' \|   ', r' λ \  ']),
      CharacterFrame([r'  o   ', r' \|-  ', r' λ \  ']),
      CharacterFrame([r'  o   ', r' \|-- ', r' λ \  ']),
      CharacterFrame([r'  o   ', r'\|--x ', r' λ \  ']),
      CharacterFrame([r'  o   ', r' /|\  ', r' λ \  ']),
    ],
    hit: [
      CharacterFrame([r'  o   ', r'/|\x  ', r' λ \  ']),
      CharacterFrame([r'  o   ', r'/|\ x ', r' λ \  ']),
      CharacterFrame([r'  o   ', r' /|\  ', r' λ \  ']),
    ],
    recover: [
      CharacterFrame([r'  o   ', r' /|\  ', r'  |   ']),
      CharacterFrame([r'  o   ', r' /|\  ', r' λ \  ']),
      CharacterFrame([r'  o   ', r' /|\  ', r' λ \  ']),
    ],
  ),

  // --------------------------------------------------------------------------
  // 노움 (Register Gnome)
  // --------------------------------------------------------------------------
  'register_gnome': RaceFrameData(
    raceId: 'register_gnome',
    idle: [
      CharacterFrame([r'  ô   ', r' /|\  ', r'  ∧   ']),
      CharacterFrame([r'  ô   ', r' /|\  ', r'  |   ']),
      CharacterFrame([r'  ô   ', r' /|\  ', r'  ∧   ']),
      CharacterFrame([r'  Ô   ', r' /|\  ', r'  ∧   ']),
    ],
    prepare: [
      CharacterFrame([r'  ô   ', r' \|\  ', r'  ∧   ']),
      CharacterFrame([r'  ô   ', r' \|   ', r'  ∧   ']),
      CharacterFrame([r'  ô   ', r' \|/  ', r'  ∧   ']),
    ],
    attack: [
      CharacterFrame([r'  ô   ', r' \|   ', r'  ∧   ']),
      CharacterFrame([r'  ô   ', r' \|*  ', r'  ∧   ']),
      CharacterFrame([r'  ô   ', r' \|** ', r'  ∧   ']),
      CharacterFrame([r'  ô   ', r'\|**> ', r'  ∧   ']),
      CharacterFrame([r'  ô   ', r' /|\  ', r'  ∧   ']),
    ],
    hit: [
      CharacterFrame([r'  ô   ', r'/|\*  ', r'  ∧   ']),
      CharacterFrame([r'  ô   ', r'/|\ * ', r'  ∧   ']),
      CharacterFrame([r'  ô   ', r' /|\  ', r'  ∧   ']),
    ],
    recover: [
      CharacterFrame([r'  ô   ', r' /|\  ', r'  |   ']),
      CharacterFrame([r'  ô   ', r' /|\  ', r'  ∧   ']),
      CharacterFrame([r'  ô   ', r' /|\  ', r'  ∧   ']),
    ],
  ),
};
