A framework-agnostic TypeScript engine that tracks interaction patterns and outputs adaptive UI state. Inspired by Designing for the 100th Use by Tanvi Palkar.
The idea: UI elements that adapt to how each user actually works. Whatever their preferred workflow or visualization pattern, the system learns from their interactions and automatically promotes what matters most — no manual configuration needed.
Click any widget repeatedly. The engine redistributes a fixed score budget — as a widget's weight grows it advances through variants, and as it shrinks it drops back down. Both views start with a pre-seeded default layout showing how implementers define a curated starting point that adapts over time.
How this differs from the original. Tanvi Palkar's demo
includes a pin feature that locks a widget in place regardless of its
score. This library deliberately omits pinning — it is a UI concern, not
an engine concern. Implementers can freeze a widget's position with CSS
(order property) or simply exclude it from any sorting
pass. The engine has no opinion on it.
The engine also returns widgets in registration order, not
sorted by score. That gives consumers two strategies: keep the original
order and let only size and variant change, or sort by score so
frequently-used widgets float to the top. The toggle below demonstrates
both approaches.