a a vibe-coded abomination experiment of a fragrance review platform built on the atmosphere. drydown.social
at main 161 lines 5.7 kB view raw
1/** 2 * Preference definitions for user fragrance settings. 3 * 4 * Each preference has 5 statement-based options that map to integer values 1-5. 5 * These preferences translate into scoring weights that personalize how reviews 6 * are evaluated. The underlying data model stores integers; these statements 7 * provide meaningful context for users. 8 */ 9 10export interface PreferenceOption { 11 value: 1 | 2 | 3 | 4 | 5 12 statement: string 13} 14 15export interface PreferenceDefinition { 16 key: PreferenceKey 17 question: string 18 description: string 19 options: readonly [PreferenceOption, PreferenceOption, PreferenceOption, PreferenceOption, PreferenceOption] 20} 21 22export type PreferenceKey = 23 | 'presenceStyle' 24 | 'longevityPriority' 25 | 'complexityPreference' 26 | 'scoringApproach' 27 28export const PREFERENCE_DEFINITIONS: Record<PreferenceKey, PreferenceDefinition> = { 29 presenceStyle: { 30 key: 'presenceStyle', 31 question: 'How do you like to be noticed?', 32 description: 'This affects how much weight projection and sillage have in your scores.', 33 options: [ 34 { value: 1, statement: 'Skin scent only — just for me' }, 35 { value: 2, statement: 'Close company — noticeable only up close' }, 36 { value: 3, statement: 'Balanced — depends on the occasion' }, 37 { value: 4, statement: 'Room presence — I enjoy being noticed' }, 38 { value: 5, statement: 'Announce myself — I like to make an entrance' }, 39 ], 40 }, 41 42 longevityPriority: { 43 key: 'longevityPriority', 44 question: 'How important is all-day longevity?', 45 description: 'This affects how much weight longevity and late-stage ratings have in your scores.', 46 options: [ 47 { value: 1, statement: 'Not important — I enjoy reapplying throughout the day' }, 48 { value: 2, statement: 'Nice to have — but not a dealbreaker' }, 49 { value: 3, statement: 'Moderately important — I appreciate good lasting power' }, 50 { value: 4, statement: 'Very important — I want it to last my workday' }, 51 { value: 5, statement: 'Essential — all-day performance is a must' }, 52 ], 53 }, 54 55 complexityPreference: { 56 key: 'complexityPreference', 57 question: 'What kind of compositions appeal to you?', 58 description: 'This affects how much weight complexity has in your scores.', 59 options: [ 60 { value: 1, statement: 'Simple and focused — I prefer clean, straightforward scents' }, 61 { value: 2, statement: 'Mostly simple — with maybe a twist or two' }, 62 { value: 3, statement: 'Balanced — I enjoy both simple and complex fragrances' }, 63 { value: 4, statement: 'Layered — I like discovering new notes over time' }, 64 { value: 5, statement: 'Intricate — the more depth and evolution, the better' }, 65 ], 66 }, 67 68 scoringApproach: { 69 key: 'scoringApproach', 70 question: 'How do you evaluate fragrances overall?', 71 description: 'This affects whether your gut feeling or technical ratings carry more weight.', 72 options: [ 73 { value: 1, statement: 'Pure instinct — my gut reaction is what matters most' }, 74 { value: 2, statement: 'Mostly instinct — but I consider the details too' }, 75 { value: 3, statement: 'Balanced — both feeling and analysis matter equally' }, 76 { value: 4, statement: 'Mostly analytical — I weigh each aspect carefully' }, 77 { value: 5, statement: 'Fully analytical — the numbers tell the real story' }, 78 ], 79 }, 80} as const 81 82/** All preference keys in order */ 83export const PREFERENCE_KEYS: readonly PreferenceKey[] = [ 84 'presenceStyle', 85 'longevityPriority', 86 'complexityPreference', 87 'scoringApproach', 88] as const 89 90/** Default preference values (balanced/neutral) */ 91export const DEFAULT_PREFERENCES: Record<PreferenceKey, number> = { 92 presenceStyle: 3, 93 longevityPriority: 5, 94 complexityPreference: 4, 95 scoringApproach: 4, 96} 97 98/** 99 * Base property importance rankings for ideal score calculation. 100 * Higher values = more important to overall score. 101 * 102 * Rankings (most to least important): 103 * 1. midProjection (1.5) - Heart projection matters most 104 * 2. openingProjection (1.45) - Initial projection 105 * 3. complexity (1.4) - Fragrance complexity 106 * 4. longevity (1.35) - Lasting power 107 * 5. sillage (1.3) - Trail/aura 108 * 6. drydownRating (1.25) - Heart quality 109 * 7. openingRating (1.2) - Opening quality 110 * 8. endRating (1.15) - Base quality 111 * 9. overallRating (1.1) - Gut check (least important) 112 */ 113export const BASE_PROPERTY_IMPORTANCE = { 114 midProjection: 1.5, 115 openingProjection: 1.45, 116 complexity: 1.4, 117 longevity: 1.35, 118 sillage: 1.3, 119 drydownRating: 1.25, 120 openingRating: 1.2, 121 endRating: 1.15, 122 overallRating: 1.1, 123} as const 124 125/** 126 * Ideal scores derived from user preferences. 127 * Represents the user's "perfect" ratings for each property. 128 */ 129export interface IdealScores { 130 // Quality ratings (always 5 - everyone wants best quality) 131 openingRating: 5 132 drydownRating: 5 133 endRating: 5 134 overallRating: 5 135 136 // Performance (from presenceStyle) 137 openingProjection: number // = presenceStyle (1-5) 138 midProjection: number // = presenceStyle (1-5) 139 sillage: number // = presenceStyle (1-5) 140 141 // Longevity (from longevityPriority) 142 longevity: number // = longevityPriority (1-5) 143 144 // Complexity (from complexityPreference) 145 complexity: number // = complexityPreference (1-5) 146} 147 148/** 149 * Property importance values (base + adjustments from scoringApproach). 150 */ 151export interface PropertyImportance { 152 openingRating: number 153 openingProjection: number 154 drydownRating: number 155 midProjection: number 156 sillage: number 157 endRating: number 158 complexity: number 159 longevity: number 160 overallRating: number 161}