fifteen/shared/src/profiles.ts
2026-03-01 21:58:53 +01:00

276 lines
9.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type { CategoryId } from "./osm-tags.js";
export const PROFILE_IDS = [
"universal",
"family",
"senior",
"professional",
"student",
] as const;
export type ProfileId = (typeof PROFILE_IDS)[number];
export interface Profile {
id: ProfileId;
label: string;
description: string;
emoji: string;
/** Suggested category weight presets (shown in sliders, range 02). */
categoryWeights: Record<CategoryId, number>;
/**
* Per-subcategory importance weights (01) used when computing grid_scores
* for this profile. Any subcategory not listed falls back to DEFAULT_SUBCATEGORY_WEIGHT.
*/
subcategoryWeights: Record<string, number>;
}
/** Fallback weight for any subcategory not explicitly listed in a profile. */
export const DEFAULT_SUBCATEGORY_WEIGHT = 0.5;
/**
* Universal subcategory weights — corrected baseline used by the "universal" profile
* and as the fallback for profile-specific overrides.
*/
export const UNIVERSAL_SUBCATEGORY_WEIGHTS: Record<string, number> = {
// ── service_trade ─────────────────────────────────────────────────────────
supermarket: 1.0, // primary grocery source — essential daily
convenience: 0.65, // corner shop fallback, often open late
pharmacy: 1.0, // health necessity
restaurant: 0.55, // daily eating / social
cafe: 0.4, // social / work spot
bank: 0.35, // branch banking — increasingly digital, visited rarely
atm: 0.2, // cash access — separate from bank branch
market: 0.4, // greengrocer, butcher, marketplace — specialty food
laundry: 0.3, // occasional need
post_office: 0.4, // administrative, rarely visited
// ── transport ─────────────────────────────────────────────────────────────
train_station: 1.0, // high-speed / intercity rail
metro: 1.0, // rapid urban transit
tram_stop: 0.75,// reliable fixed-route urban
bus_stop: 0.55,// basic PT — variable frequency/quality
ferry: 0.5, // situational but important where present
bike_share: 0.5, // active mobility option
car_share: 0.5, // car access without ownership
// ── work_school ───────────────────────────────────────────────────────────
school: 0.7, // compulsory education — essential for families, not universal
driving_school: 0.2, // niche, occasional — rarely a walkability factor
kindergarten: 0.75, // essential for young families
university: 0.55, // higher education — relevant to students/young adults
coworking: 0.55, // remote / flexible work
office: 0.1, // landuse centroid — not a meaningful walkable destination
// ── culture_community ─────────────────────────────────────────────────────
hospital: 1.0, // critical healthcare
clinic: 0.8, // routine healthcare
library: 0.7, // education + community hub
community_center: 0.6, // social infrastructure
social_services: 0.6, // vital for those who need it
theatre: 0.5, // cultural enrichment
place_of_worship: 0.25,// highly variable relevance
government: 0.4, // administrative
museum: 0.4, // cultural enrichment
// ── recreation ────────────────────────────────────────────────────────────
park: 1.0, // daily green space
playground: 0.85,// family essential
sports_facility: 0.65,// active recreation
gym: 0.65,// fitness
green_space: 0.6, // passive nature (forest, meadow, grass)
swimming_pool: 0.55,// seasonal / activity-specific
};
export const PROFILES: Record<ProfileId, Profile> = {
universal: {
id: "universal",
label: "Universal",
description: "Balanced across all resident types",
emoji: "⚖️",
categoryWeights: {
service_trade: 1.0,
transport: 1.0,
work_school: 1.0,
culture_community: 1.0,
recreation: 1.0,
},
subcategoryWeights: UNIVERSAL_SUBCATEGORY_WEIGHTS,
},
family: {
id: "family",
label: "Young Family",
description: "Families with young children — schools, playgrounds, healthcare",
emoji: "👨‍👩‍👧",
categoryWeights: {
service_trade: 1.2,
transport: 1.0,
work_school: 1.5,
culture_community: 0.9,
recreation: 1.4,
},
subcategoryWeights: {
...UNIVERSAL_SUBCATEGORY_WEIGHTS,
// school & childcare — essential for this group
school: 1.0,
kindergarten: 1.0,
// daily shopping
supermarket: 1.0,
convenience: 0.7,
pharmacy: 1.0,
// healthcare for children
clinic: 1.0,
hospital: 0.9,
// outdoor play
playground: 1.0,
park: 1.0,
green_space: 0.75,
sports_facility: 0.7,
// less relevant to families with young children
cafe: 0.3,
restaurant: 0.45,
gym: 0.5,
university: 0.2,
coworking: 0.25,
office: 0.05,
theatre: 0.3,
museum: 0.35,
bar: 0.0,
},
},
senior: {
id: "senior",
label: "Senior",
description: "Older residents — healthcare, local services, green space",
emoji: "🧓",
categoryWeights: {
service_trade: 1.4,
transport: 1.1,
work_school: 0.3,
culture_community: 1.5,
recreation: 1.0,
},
subcategoryWeights: {
...UNIVERSAL_SUBCATEGORY_WEIGHTS,
// healthcare — top priority
hospital: 1.0,
clinic: 1.0,
pharmacy: 1.0,
social_services: 0.9,
// daily essentials
supermarket: 1.0,
convenience: 0.8,
// social & community
community_center: 0.9,
library: 0.8,
cafe: 0.55, // social outings matter
restaurant: 0.45,
// accessible green space
park: 1.0,
green_space: 0.75,
// transit (many don't drive)
bus_stop: 0.75,
tram_stop: 0.8,
metro: 0.8,
train_station: 0.75,
// not relevant
school: 0.05,
kindergarten: 0.05,
university: 0.15,
coworking: 0.05,
office: 0.0,
playground: 0.3,
gym: 0.5,
swimming_pool: 0.5,
},
},
professional: {
id: "professional",
label: "Young Professional",
description: "Working adults without children — transit, fitness, dining",
emoji: "💼",
categoryWeights: {
service_trade: 1.0,
transport: 1.5,
work_school: 0.7,
culture_community: 0.9,
recreation: 1.1,
},
subcategoryWeights: {
...UNIVERSAL_SUBCATEGORY_WEIGHTS,
// transit — high priority for commuters
metro: 1.0,
train_station: 1.0,
tram_stop: 0.85,
bus_stop: 0.65,
bike_share: 0.7,
// fitness & dining
gym: 0.9,
sports_facility: 0.7,
swimming_pool: 0.65,
restaurant: 0.75,
cafe: 0.7,
// daily essentials
supermarket: 1.0,
pharmacy: 0.85,
// work
coworking: 0.85,
// less relevant
school: 0.1,
kindergarten: 0.05,
playground: 0.15,
university: 0.35,
office: 0.05,
social_services: 0.4,
},
},
student: {
id: "student",
label: "Student",
description: "Students — university, library, cafés, transit, budget services",
emoji: "🎓",
categoryWeights: {
service_trade: 0.9,
transport: 1.4,
work_school: 1.5,
culture_community: 1.2,
recreation: 0.8,
},
subcategoryWeights: {
...UNIVERSAL_SUBCATEGORY_WEIGHTS,
// education
university: 1.0,
library: 1.0,
coworking: 0.9,
// social
cafe: 0.9,
restaurant: 0.65,
// transit
metro: 1.0,
train_station: 0.9,
tram_stop: 0.8,
bus_stop: 0.7,
bike_share: 0.85,
// budget shopping
supermarket: 0.9,
convenience: 0.75,
pharmacy: 0.75,
// culture
museum: 0.55,
theatre: 0.5,
community_center: 0.6,
// recreation
gym: 0.75,
sports_facility: 0.65,
park: 0.75,
// not relevant
school: 0.05,
kindergarten: 0.05,
office: 0.05,
playground: 0.2,
},
},
};