The Wave suite was eight products re-solving the same interface problems apart from each other. Wavi is the layer we extracted so they stopped — and then released under MIT.

Components in one package
Wave products on the shared layer
Commands to set it up
Languages from one build
01 — Context
The challenge
Eight products. One team. Every one of them needed the same things: a date picker, a data table, a money input, an application shell with a rail and a command palette.
Each had its own. Not by decision — by accumulation. WavePay's amount field rounded taka one way, WaveCommerce's another. Three products had three date pickers, and only one of them rendered Bangla digits. A +880 phone input existed four times, validated four ways, and two of them rejected numbers that are perfectly valid.
The cost was not the duplication. It was that a fix only ever landed in one place. A bug found in WaveHR's table was still live in WaveGrid, and nobody could say which products shared the defect without opening all of them. Design drift followed the same path: the suite looked like eight products from eight companies, because in every way that mattered to the code, it was.
The specifically Bangladeshi parts were the worst of it. bKash and Nagad payment selection, taka formatting with the right separators, NID capture, division-and-district addresses, Bangla dates and Bangla digits — none of this comes in an off-the-shelf component library. So it was written from scratch each time, by whoever was on that product that month, and the rules were only as correct as that person's memory of them.
02 — What we built
The solution
We stopped treating the shared layer as something each product owned a copy of, and made it a package.
One source for the primitives. Inputs, pickers, dialogs, menus, tabs, tables and the application shell — rail to panel to content to drawer, with ⌘K — extracted into @waveinno/ui. Over a hundred components, each file opening with a comment stating what it is for, so the next person does not have to infer it.
Tokens instead of overrides. The whole set themes from one colour and one radius, on Tailwind CSS 4, in light and dark. A product that needs to look different sets tokens; it does not fork a component. That single rule is what keeps the suite from drifting apart again.
The local rules, written once and correct. Taka amounts, bKash and Nagad pickers, +880 numbers, NID fields, division-district address capture, Bangla dates and Bangla digits — as components, with the formatting settled in one place. Every string on screen arrives through a prop, so English and Bangla are the same build.
Setup that cannot be got wrong. npx @waveinno/ui init asks whether the project is Next.js or React with Vite, which currency, which package manager — then shows every change before it makes one. It writes the stylesheet, fonts, providers and theme script, installs the package and Tailwind, and never overwrites a file that already exists. doctor checks an installation that is already there.
Then we published it. MIT licensed, with documentation and a playground, because a component library that only its authors can read is a liability the day its authors move on.
Built with