/ buddy / types.ts
types.ts
  1  export const RARITIES = [
  2    'common',
  3    'uncommon',
  4    'rare',
  5    'epic',
  6    'legendary',
  7  ] as const
  8  export type Rarity = (typeof RARITIES)[number]
  9  
 10  // One species name collides with a model-codename canary in excluded-strings.txt.
 11  // The check greps build output (not source), so runtime-constructing the value keeps
 12  // the literal out of the bundle while the check stays armed for the actual codename.
 13  // All species encoded uniformly; `as` casts are type-position only (erased pre-bundle).
 14  const c = String.fromCharCode
 15  // biome-ignore format: keep the species list compact
 16  
 17  export const duck = c(0x64,0x75,0x63,0x6b) as 'duck'
 18  export const goose = c(0x67, 0x6f, 0x6f, 0x73, 0x65) as 'goose'
 19  export const blob = c(0x62, 0x6c, 0x6f, 0x62) as 'blob'
 20  export const cat = c(0x63, 0x61, 0x74) as 'cat'
 21  export const dragon = c(0x64, 0x72, 0x61, 0x67, 0x6f, 0x6e) as 'dragon'
 22  export const octopus = c(0x6f, 0x63, 0x74, 0x6f, 0x70, 0x75, 0x73) as 'octopus'
 23  export const owl = c(0x6f, 0x77, 0x6c) as 'owl'
 24  export const penguin = c(0x70, 0x65, 0x6e, 0x67, 0x75, 0x69, 0x6e) as 'penguin'
 25  export const turtle = c(0x74, 0x75, 0x72, 0x74, 0x6c, 0x65) as 'turtle'
 26  export const snail = c(0x73, 0x6e, 0x61, 0x69, 0x6c) as 'snail'
 27  export const ghost = c(0x67, 0x68, 0x6f, 0x73, 0x74) as 'ghost'
 28  export const axolotl = c(0x61, 0x78, 0x6f, 0x6c, 0x6f, 0x74, 0x6c) as 'axolotl'
 29  export const capybara = c(
 30    0x63,
 31    0x61,
 32    0x70,
 33    0x79,
 34    0x62,
 35    0x61,
 36    0x72,
 37    0x61,
 38  ) as 'capybara'
 39  export const cactus = c(0x63, 0x61, 0x63, 0x74, 0x75, 0x73) as 'cactus'
 40  export const robot = c(0x72, 0x6f, 0x62, 0x6f, 0x74) as 'robot'
 41  export const rabbit = c(0x72, 0x61, 0x62, 0x62, 0x69, 0x74) as 'rabbit'
 42  export const mushroom = c(
 43    0x6d,
 44    0x75,
 45    0x73,
 46    0x68,
 47    0x72,
 48    0x6f,
 49    0x6f,
 50    0x6d,
 51  ) as 'mushroom'
 52  export const chonk = c(0x63, 0x68, 0x6f, 0x6e, 0x6b) as 'chonk'
 53  
 54  export const SPECIES = [
 55    duck,
 56    goose,
 57    blob,
 58    cat,
 59    dragon,
 60    octopus,
 61    owl,
 62    penguin,
 63    turtle,
 64    snail,
 65    ghost,
 66    axolotl,
 67    capybara,
 68    cactus,
 69    robot,
 70    rabbit,
 71    mushroom,
 72    chonk,
 73  ] as const
 74  export type Species = (typeof SPECIES)[number] // biome-ignore format: keep compact
 75  
 76  export const EYES = ['·', '✦', '×', '◉', '@', '°'] as const
 77  export type Eye = (typeof EYES)[number]
 78  
 79  export const HATS = [
 80    'none',
 81    'crown',
 82    'tophat',
 83    'propeller',
 84    'halo',
 85    'wizard',
 86    'beanie',
 87    'tinyduck',
 88  ] as const
 89  export type Hat = (typeof HATS)[number]
 90  
 91  export const STAT_NAMES = [
 92    'DEBUGGING',
 93    'PATIENCE',
 94    'CHAOS',
 95    'WISDOM',
 96    'SNARK',
 97  ] as const
 98  export type StatName = (typeof STAT_NAMES)[number]
 99  
100  // Deterministic parts — derived from hash(userId)
101  export type CompanionBones = {
102    rarity: Rarity
103    species: Species
104    eye: Eye
105    hat: Hat
106    shiny: boolean
107    stats: Record<StatName, number>
108  }
109  
110  // Model-generated soul — stored in config after first hatch
111  export type CompanionSoul = {
112    name: string
113    personality: string
114  }
115  
116  export type Companion = CompanionBones &
117    CompanionSoul & {
118      hatchedAt: number
119    }
120  
121  // What actually persists in config. Bones are regenerated from hash(userId)
122  // on every read so species renames don't break stored companions and users
123  // can't edit their way to a legendary.
124  export type StoredCompanion = CompanionSoul & { hatchedAt: number }
125  
126  export const RARITY_WEIGHTS = {
127    common: 60,
128    uncommon: 25,
129    rare: 10,
130    epic: 4,
131    legendary: 1,
132  } as const satisfies Record<Rarity, number>
133  
134  export const RARITY_STARS = {
135    common: '★',
136    uncommon: '★★',
137    rare: '★★★',
138    epic: '★★★★',
139    legendary: '★★★★★',
140  } as const satisfies Record<Rarity, string>
141  
142  export const RARITY_COLORS = {
143    common: 'inactive',
144    uncommon: 'success',
145    rare: 'permission',
146    epic: 'autoAccept',
147    legendary: 'warning',
148  } as const satisfies Record<Rarity, keyof import('../utils/theme.js').Theme>