Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ The kits below cover all of those. The API is composable: a unit from one kit co
- [**`cooking`**](https://simiancraft.github.io/unitforge/#/cooking): recipe scaling across US/UK/metric cup variants; cooking-tradition packaging (stick of butter, EU butter block, dash, pinch); heat descriptors. Demo includes the soda-vs-sugar comparator.
- [**`data-storage`**](https://simiancraft.github.io/unitforge/#/data-storage): bytes (decimal and IEC binary), bits; the GB-vs-GiB and Gbit-vs-MB confusion you keep explaining.
- [**`astronomy`**](https://simiancraft.github.io/unitforge/#/astronomy): solar-system to cosmological distance (au, ly, pc, kpc/Mpc/Gpc, light-second through light-hour) per IAU 2012 / 2015 resolutions. Demo flies you through a live BabylonJS solar system, then turns H0 into the age of the universe, distances into light-travel time, interstellar trips into generations of tortoises, and the Sun into a grain of sand.
- [**`antiquity`**](https://simiancraft.github.io/unitforge/#/antiquity): ~90 atoms across 8 civilizations (Egyptian, Mesopotamian, Greek, Roman, Hebrew, Chinese, Japanese, and pre-1835 English). Classics translation, numismatic mass, archaeological analysis. Not for clinical or commercial use; reach for it when you're reading Herodotus. Demo includes the rulers-of-empire length comparator and the coin scale.
- [**`antiquity`**](https://simiancraft.github.io/unitforge/#/antiquity): ~90 atoms across 8 civilizations (Egyptian, Mesopotamian, Greek, Roman, Hebrew, Chinese, Japanese, and pre-1835 English). Classics translation, numismatic mass, archaeological analysis. Not for clinical or commercial use; reach for it when you're reading Herodotus. Demo includes the rulers-of-empire length comparator, the coin scale, and a "how tall is your CEO?" height comparator that reads a modern height back in ancient cubits.

**Atomic building blocks** (use directly when no domain kit fits, or compose your own kit on top):

Expand Down
2 changes: 2 additions & 0 deletions demo/src/components/kits/antiquity/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { Bench, type BenchState } from '../bench.js';
import { KitLayout } from '../layout.js';
import type { KitMeta } from '../registry.js';
import { AntiquityBackdrop } from './parts/antiquity-backdrop.js';
import { CeoStature } from './sections/ceo-stature/index.js';
import { CoinScale } from './sections/coin-scale/index.js';
import { HelloAntiquity } from './sections/hello-antiquity.js';
import { RulersOfEmpire } from './sections/rulers-of-empire/index.js';
Expand Down Expand Up @@ -76,6 +77,7 @@ export function AntiquityScreen() {
<HelloAntiquity />
<RulersOfEmpire />
<CoinScale />
<CeoStature />
</>
}
/>
Expand Down
187 changes: 187 additions & 0 deletions demo/src/components/kits/antiquity/sections/ceo-stature/figures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
// The roster for the "how tall is your CEO?" section: the child catalog
// the stature gauge picks from. Two kinds, surfaced as optgroups: tech
// `exec`s and historical `leader`s. Heights are in inches.
//
// Honesty note: every height here is a popularly-reported, approximate
// figure, not a verified measurement. Living execs rarely publish a
// height, and historical figures' heights are heavily mythologized
// (Napoleon's is itself a correction of a myth). The section renders a
// disclaimer saying as much; this catalog is for amusement, not records.

export type FigureKind = 'exec' | 'leader';

export interface Figure {
/** Stable id for the picker + default lookups. */
id: string;
/** Display name. */
name: string;
/** Org (execs) or title (leaders), shown as the sublabel. */
role: string;
/** Popularly-reported height in inches. */
heightInches: number;
/** Optgroup bucket. */
kind: FigureKind;
/** Optional emoji shown beside the name in the picker and above the
* figure on the ruler. */
badge?: string;
}

/** The whole roster, ascending by reported height within each kind
* (the author is pinned first among the execs). */
export const FIGURES: readonly Figure[] = [
// Executives
{
id: 'the-simian',
name: 'Jesse Harlin',
role: 'Simiancraft',
heightInches: 66,
kind: 'exec',
badge: '🐵',
},
{ id: 'jack-ma', name: 'Jack Ma', role: 'Alibaba', heightInches: 64, kind: 'exec' },
{ id: 'mark-zuckerberg', name: 'Mark Zuckerberg', role: 'Meta', heightInches: 67, kind: 'exec' },
{ id: 'jensen-huang', name: 'Jensen Huang', role: 'NVIDIA', heightInches: 67, kind: 'exec' },
{ id: 'jeff-bezos', name: 'Jeff Bezos', role: 'Amazon', heightInches: 67, kind: 'exec' },
{
id: 'michael-bloomberg',
name: 'Michael Bloomberg',
role: 'Bloomberg',
heightInches: 67,
kind: 'exec',
},
{ id: 'eric-yuan', name: 'Eric Yuan', role: 'Zoom', heightInches: 67, kind: 'exec' },
{ id: 'tony-xu', name: 'Tony Xu', role: 'DoorDash', heightInches: 67, kind: 'exec' },
{ id: 'sergey-brin', name: 'Sergey Brin', role: 'Google', heightInches: 68, kind: 'exec' },
{ id: 'satya-nadella', name: 'Satya Nadella', role: 'Microsoft', heightInches: 69, kind: 'exec' },
{ id: 'bill-gates', name: 'Bill Gates', role: 'Microsoft', heightInches: 70, kind: 'exec' },
{ id: 'sundar-pichai', name: 'Sundar Pichai', role: 'Alphabet', heightInches: 70, kind: 'exec' },
{
id: 'warren-buffett',
name: 'Warren Buffett',
role: 'Berkshire Hathaway',
heightInches: 70,
kind: 'exec',
},
{ id: 'larry-page', name: 'Larry Page', role: 'Google', heightInches: 71, kind: 'exec' },
{ id: 'larry-ellison', name: 'Larry Ellison', role: 'Oracle', heightInches: 72, kind: 'exec' },
{ id: 'elon-musk', name: 'Elon Musk', role: 'Tesla · SpaceX', heightInches: 73, kind: 'exec' },
{ id: 'steve-jobs', name: 'Steve Jobs', role: 'Apple', heightInches: 74, kind: 'exec' },
{ id: 'tim-cook', name: 'Tim Cook', role: 'Apple', heightInches: 75, kind: 'exec' },
// Leaders
{
id: 'benito-juarez',
name: 'Benito Juárez',
role: 'President of Mexico',
heightInches: 54,
kind: 'leader',
},
{
id: 'deng-xiaoping',
name: 'Deng Xiaoping',
role: 'Paramount leader of China',
heightInches: 59,
kind: 'leader',
},
{
id: 'queen-victoria',
name: 'Queen Victoria',
role: 'Queen of the UK',
heightInches: 60,
kind: 'leader',
},
{
id: 'elizabeth-ii',
name: 'Elizabeth II',
role: 'Queen of the UK',
heightInches: 62,
kind: 'leader',
},
{
id: 'james-madison',
name: 'James Madison',
role: 'US President',
heightInches: 64,
kind: 'leader',
},
{
id: 'joseph-stalin',
name: 'Joseph Stalin',
role: 'Soviet leader',
heightInches: 65,
kind: 'leader',
},
{
id: 'napoleon',
name: 'Napoleon Bonaparte',
role: 'Emperor of the French',
heightInches: 66,
kind: 'leader',
},
{
id: 'harry-truman',
name: 'Harry S. Truman',
role: 'US President',
heightInches: 68,
kind: 'leader',
},
{
id: 'dwight-eisenhower',
name: 'Dwight D. Eisenhower',
role: 'US President',
heightInches: 69.5,
kind: 'leader',
},
{
id: 'mary-queen-of-scots',
name: 'Mary, Queen of Scots',
role: 'Queen of Scotland',
heightInches: 71,
kind: 'leader',
},
{
id: 'henry-viii',
name: 'Henry VIII',
role: 'King of England',
heightInches: 74,
kind: 'leader',
},
{
id: 'george-washington',
name: 'George Washington',
role: 'US President',
heightInches: 74,
kind: 'leader',
},
{
id: 'lyndon-johnson',
name: 'Lyndon B. Johnson',
role: 'US President',
heightInches: 75.5,
kind: 'leader',
},
{ id: 'edward-iv', name: 'Edward IV', role: 'King of England', heightInches: 76, kind: 'leader' },
{
id: 'abraham-lincoln',
name: 'Abraham Lincoln',
role: 'US President',
heightInches: 76,
kind: 'leader',
},
{
id: 'peter-the-great',
name: 'Peter the Great',
role: 'Tsar of Russia',
heightInches: 80,
kind: 'leader',
},
];

export const EXECS: readonly Figure[] = FIGURES.filter((f) => f.kind === 'exec');
export const LEADERS: readonly Figure[] = FIGURES.filter((f) => f.kind === 'leader');

/** Slider domain for free-entry and the ruler's X axis, in inches. */
export const STATURE_MIN_IN = 48; // 4'0"
export const STATURE_MAX_IN = 90; // 7'6"

export const DEFAULT_SUBJECT_ID = 'the-simian';
export const DEFAULT_REFERENCE_ID = 'peter-the-great';
109 changes: 109 additions & 0 deletions demo/src/components/kits/antiquity/sections/ceo-stature/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// "How tall is your CEO?" The kit's flagship section. Two people (tech
// execs, world leaders, or a free-entered height) are laid on a human-
// scale ruler as a stair-step, compared as a percentage, then reforged
// into an ancient unit. The whole point of the antiquity kit in one
// playful surface: a modern, human-scale length expressed the way an
// ancient scribe would have measured it.
//
// Ontology: the feature is a *height comparison*; its children are
// *figures* (figures.ts). State lives in useStatureGauge; the zones
// (ruler, two pickers, the center reading, the ancient readout) are
// pure renderers of resolved sides.

import { Ruler } from 'lucide-react';
import { forge } from 'unitforge';
import { centimeter, inch } from 'unitforge/kits/antiquity';
import { CodeBlock } from '~/components/ui/code-block.js';
import { formatMagnitude, toJsName } from '~/lib/format.js';
import { findById } from '~/lib/units.js';
import { SectionHeader, SectionLayout, WidgetLayout } from '../../../section-layout.js';
import { ANTIQUITY_LENGTH_BENCH } from '../../units.js';
import { AncientReadout } from './parts/ancient-readout.js';
import { ComparisonReadout } from './parts/comparison-readout.js';
import { StaturePicker } from './parts/stature-picker.js';
import { StatureRuler } from './parts/stature-ruler.js';
import { ftIn, type ResolvedSide } from './stature-model.js';
import { useStatureGauge } from './use-stature-gauge.js';

const inchToCm = forge(inch, centimeter);

// Three forge lines: each person's height into centimeters (commented
// with who they are), then the subject's height into the chosen ancient
// unit. The whole point of the section in one snippet.
function buildCode(subject: ResolvedSide, reference: ResolvedSide, unitId: string): string {
const unit = findById(ANTIQUITY_LENGTH_BENCH, unitId);
const ancient = forge(inch, unit);
const line = (s: ResolvedSide) =>
`forge(inch, centimeter)(${s.heightInches}); // ${s.label}, ${ftIn(s.heightInches)} = ${inchToCm(s.heightInches).toFixed(1)} cm`;
return [
line(subject),
line(reference),
`forge(inch, ${toJsName(unit.id)})(${subject.heightInches}); // in ancient units = ${formatMagnitude(ancient(subject.heightInches))} ${unit.symbol}`,
].join('\n');
}

export function CeoStature() {
const g = useStatureGauge();
return (
<SectionLayout
id="ceo-stature"
headerZone={
<SectionHeader
eyebrow="demo 04"
title="how tall is your CEO?"
kicker="height, to scale, then in cubits"
iconZone={<Ruler size={28} strokeWidth={1.5} className="text-uf-accent" />}
/>
}
introZone={
<>
Pick two people, or dial in a custom height; the slider runs in inches and projects to
feet and inches (and centimeters) live. The ruler drops each figure onto a four-to-seven-
and-a-half-foot scale as a stair-step, the center reads one as a percentage of the other,
and the bottom row reforges both heights into the ancient unit of your choice.
</>
}
widgetZone={
<WidgetLayout
interactionZone={
<div className="flex flex-col gap-5">
<StatureRuler subject={g.resolvedSubject} reference={g.resolvedReference} />
<div className="grid items-start gap-4 sm:grid-cols-[1fr_13rem_1fr]">
<StaturePicker
label="your CEO"
side={g.subject}
onChange={g.setSubject}
accent="var(--uf-accent)"
customCtaLabel="custom CEO"
/>
<ComparisonReadout subject={g.resolvedSubject} reference={g.resolvedReference} />
<StaturePicker
label="compared to"
side={g.reference}
onChange={g.setReference}
accent="var(--uf-accent-2)"
customCtaLabel="custom person"
/>
</div>
<AncientReadout
subject={g.resolvedSubject}
reference={g.resolvedReference}
unitId={g.ancientUnitId}
onUnit={g.setAncientUnitId}
/>
</div>
}
codeZone={
<CodeBlock code={buildCode(g.resolvedSubject, g.resolvedReference, g.ancientUnitId)} />
}
/>
}
notesZone={
<>
Heights are popularly reported, approximate figures, gathered for amusement and not
verified; historical figures' heights especially are mythologized.
</>
}
/>
);
}
Loading