Introduction
Loyalty Patterns is a set of React components for the customer-facing side of loyalty and gamification programs: scratch cards, spin wheels, points counters, stamp cards, tier progress, referral widgets. The surfaces a member actually touches.
It is not an admin panel, and it is not a design system. It assumes you already have one.
Why this exists
Loyalty programs are largely a solved problem on the backend. Campaign engines, rules, ledgers and fulfilment are mature and mostly headless. What ships late, and usually twice, is the member-facing layer. It is harder than it looks, in four specific ways:
- The outcome cannot be decided in the browser. A scratch card over a
client-side
Math.random()is a compliance incident waiting for a curious DevTools user. Every chance mechanic here reveals a result the server already decided. - Gesture mechanics have an accessibility floor. Scratching is a path-based gesture, and WCAG 2.5.1 requires an equivalent single-pointer path. That is structural, not a setting.
- Every campaign is multi-brand. The same mechanic ships against dozens of visual identities, so theming cannot be a fork.
- Odds disclosure has to live somewhere designed. Not in a footer nobody reads, and not bolted on at review time.
These components are opinionated about exactly those four things, and deliberately unopinionated about everything else.
What you get
Every component is a folder you copy. There is no package to install and
no runtime dependency beyond React. A folder plus tokens.css is a
working install.
Components read only --lk-* CSS custom properties. That is the
whole theming interface, which is what lets a MUI app, a shadcn app, a
Tailwind app and a plain-CSS app all adopt the same component with about
twenty lines of token mapping.
What you also get: a prompt
Copy-in distribution has a hard edge: it only helps React. If you are on
Vue, Svelte, SwiftUI or React Native, a folder of .tsx is worth
nothing to you.
So every component in the playground also emits a portable specification — a prompt carrying the behaviour contract, the accessibility requirements, the state machine and the compliance rules, with the reasoning attached to each one, and explicitly separating the invariants from the React-specific notes you should adapt rather than copy.
Hand it to a coding agent in your own stack and you get an implementation that honours the same contract. The component is the reference implementation; the prompt is the specification. That is the part which travels.
Where to start
Components are added when they meet the standard above, not to fill out a set. What exists is listed in the sidebar and runs live in the playground; the changelog says what has shipped and what is planned.
If you want to judge whether the standard is worth anything, read the scratch card documentation and judge it on the parts that are inconvenient.