I shape everyday tools for any screen. I start with how a person thinks, feels and tires, make the call on what a product should be, and carry it through craft and code until it works in their hands.
One product, designed as a system: engine, themes, a global-ready layout, a web app and a reader built for long texts.
Explore the workI am an artist and a technical designer. Everything I put in front of people is something I have drawn, built and tested myself, on phones, on the web and on every screen in between.
On Texi I am the only designer, so I own visual design, UX and art direction from first sketch to release. I set the direction, make the calls and build what I decide, in Jetpack Compose and Material 3, tested on real phones so that what I draw is what people hold.
Before a pixel moves, I ask what the thing is for and what it must never do. Texi's answer became the brief for every screen.
People hesitate in front of too many choices, rush past small print and trust what looks calm. So I remove the third button, stage the filters, and keep success on screen long enough to be felt.
A small phone in bright light, a very long text, a language read from the other direction, a screen reader. I begin with the person who has the least patience and the most at stake, and everyone else is served along the way.
I frame the problem, weigh the options, make the call and carry it through build and testing, explaining the reason at every step.
I find the pattern behind repeated screens and turn it into one component.
I choose colour and type by eye and by rule, so the product feels hand-made and stays readable in every theme and script.
I design layouts that work for both reading directions from the start, instead of patching screen by screen.
I put accessibility into the rules that generate every screen, so nobody has to remember it at the end.
When real use shows a problem, I reverse my own decision and say so.
| Area | What I do | See |
|---|---|---|
| Product and UX design | Design thinking from empathize to test, run on a live product | Design process |
| Design systems | Parametric components, one spec reused across features | 01 Engine, 10 Card pages |
| Visual systems | Colour science, procedural frames and patterns, elevation, motion | 02 Themes |
| Localization and RTL | Logical layout, auto-mirrored icons, per-script typography, verification | 03 Global |
| Information design | Material 3 web app structure, staged filters, reading and typography | 04 Web app, 05 Filters, 06 Reader |
| Interaction design | Bottom sheets, progress, Save or Discard, Surprise me | 07 Patterns |
| Accessibility | Contrast engine, screen-reader coverage, help kept in sync with the UI | 08 Accessibility |
| Product principles | Turning a product's limits into concrete interface decisions | 09 Principles |
| Front-end fluency | Building UI in Compose with small, reviewable commits | Design process |
Texi is a reading and writing platform for plain text: tens of thousands of free ebooks, user-made quote cards, and a book reader built for long texts in any language, whether it reads left to right or right to left. These case studies are about how the interface carries all of the personality without becoming noisy.
Texi lets people dress their own text: the cover of a book, their public profile, an invite card they send to friends, and the quote cards that are the heart of the app. Each feature began life with its own bespoke editor. This is the story of collapsing them into one.
Cover, Design Profile, Invite and Quote Decoration each offered colour, frame, pattern and font choices, but each had been built separately, at a different moment, by a different assumption. A frame in the invite editor was not the same frame as in the quote editor. Pickers sat in different positions, used different interaction models, and a user who learned one had to relearn the next. For engineering it meant four codepaths to fix every time a design changed.
I laid the four editors side by side and listed every control. The overlap was far larger than the differences. Every feature was really asking the same five questions about a rectangle of text:
| Axis | Options | Cover | Profile | Invite | Quote |
|---|---|---|---|---|---|
| Colour | Theme-aware palette + custom | ● | ● | ● | ● |
| Frame | 10 styles | ● | ● | ● | ● |
| Pattern | 20 styles | ● | ● | ● | ● |
| Background / texture | 9 backgrounds, 10 textures | ● | ● | ● | ● |
| Font & size | Fonts tuned per script | ● | ● | ● |
Only the content differed: a title and author on a cover, a name on a profile, an invitation line, a quote. The decoration layer was the same four times over.
One state object. A single decoration spec — colour, frame, pattern, background, texture, size, font — is the only input. Each feature owns its content slot and passes the spec in. Saving, restoring and sharing a design is serialising one small object.
Procedural rendering. Frames, patterns and textures are drawn in Compose from the user's chosen colour, rather than loaded from bitmap sets. This keeps the app almost entirely vector, means every treatment works in every theme and in day and night, and keeps the install small.
One picker. A single customization-picker component renders every axis: a horizontally scrolling row of previews, each preview being the real renderer at thumbnail size, so what you tap is exactly what you get.
Surfaces as thin hosts. Cover, Profile, Invite and Quote became thin hosts around the same engine. Adding a fifth surface is a content slot and a preview, not a design project.
The first draft of anything is plain text.— Texi
A grid of choices is a daunting thing to face when you just want something nice. So every picker carries a Surprise me action. It randomises each axis independently and obeys one rule: no axis may repeat its previous value. Colour uses a true shuffle-bag, so all options cycle before any repeats, which stops the "it keeps giving me the same teal" feeling that plain random produces.
The same picker, spec and save behaviour carry over to the app's other editing screens (case study 07).
Next: publish the engine as an internal Design System artifact with token pages so the web app can mirror the same five axes in CSS.
Texi is a product where colour is the content's frame. The first palette was a handful of hand-picked colours. This case study is about how it grew into a curated set without turning into a swatch dump, and how each of them stays legible in both day and night.
Letting people choose a colour is easy. Making the entire app — buttons, cards, navigation, icons, the book reader — look intentional in any colour is hard. A flat list of accent colours would give forty-six ways to get contrast wrong, and users would meet only the ones that happen to look good.
I grouped themes by how a person describes their taste rather than by hue. Each paradigm answers a different feeling.
| Paradigm | Count | Idea | How the scheme is built |
|---|---|---|---|
| Content | 12 | "One colour, and let the app follow." Closest to Material You. | A single seed generates the whole tonal scheme. |
| Duo-tone | 11 | "Two colours that belong together", e.g. a turquoise-and-sand pairing. | Primary from colour A, secondary and surfaces drawn from B. |
| Tri-tone | 13 | "A flag, a season, a mood." Includes a national-flag tri-tone. | Three seeds mapped to primary, secondary and tertiary roles. |
| Monochromatic | 10 | "Calm." One hue, many tones, nothing competing with the text. | One hue, with chroma deliberately reduced across surfaces. |
The mapping is also a user-facing taxonomy. Settings exposes Content, Duo, Tri and Mono as four tabs. Four short groups are scannable; one list of forty-six is not.
ColorScheme is built when needed, for both light and dark, so there is never a hand-edited palette drifting out of sync.Left: text colour found by binary search on lightness until contrast clears the floor. Right: plain white, which fails on light and mid-tones.
Texi's library spans scripts and directions: right-to-left (RTL) and left-to-right (LTR) scripts sit side by side; some scripts join and stack their letters; some have no spaces between words; and long translations stretch every button label. The goal was not translation. It was a layout system that does not break when the words change.
A UI designed in one language quietly assumes that text is short, left-aligned and sits to the right of its icon. Right-to-left readers were the first to find where that assumption breaks. Fixing screens one by one would never end; the fix had to be a rule.
Logical, not physical. Layouts use start and end rather than left and right: padding, alignment, arrangement and swipe direction all mirror automatically with the locale.
Framework mirroring for icons. Directional icons (back, forward, chevron, send) use the auto-mirrored icon set: 22 distinct icons across 47 usages, with zero manual flips. Non-directional icons, such as play or a clock, are intentionally not mirrored.
Fonts per script. A bundled catalogue of 16 typefaces: 8 platform-generic Latin and 8 for right-to-left scripts, each labelled in its own script, with mirrored picker rows. Reading mode defaults for size and line-height are tuned per script because tall, calligraphic scripts need far more vertical room than Latin.
Language list from the source. The in-app language picker is generated from the module's declared locale configuration, not from whatever locales happen to exist at runtime, so a missing translation can never show up as a selectable language.
| Check | Method | What it catches |
|---|---|---|
| Direction | Launch every primary flow in each RTL language | Un-mirrored icons, wrong swipe direction, off-edge padding |
| Length stress | Run the longest translations, and scripts with tall or joined letters, through every button and chip | Truncated labels, broken chip rows, clipped sheets |
| Script metrics | Test CJK, Indic and calligraphic scripts in the reader | Clipped ascenders, line-height too tight, missing glyphs |
| Help parity | One help file per locale, 1:1 with the UI | Docs that describe screens that do not exist in that language |
| Real devices | Two physically different phones | Inset and density bugs invisible in emulators |
Texi began as an Android app. The web version had to serve the same library of tens of thousands of free books on a large screen, work for visitors who are not signed in, and stay true to the product's own rules. I redesigned its structure in Material 3 with its own design system.
The web app opens straight into the catalogue: anyone can browse, search and filter without signing in, and sign-in only unlocks the Library, Subscriptions and other personal features. The feed has five ways to narrow it (language, publisher, author, price, type). On a desktop that raises three design questions. Where does navigation live? Where do filters live so they are always reachable? And how does a very large library stay the hero rather than getting buried in controls?
Routes as places. The app is a set of hash-routed views: posts, library, subscriptions, bookmarks, text editor, settings and statistics. The rail's destinations map onto these routes, so adding a view means one route and one rail entry.
Guests first. Library and Subscriptions are the only gated areas, and visitors who tap them are sent to sign in. Everything else is open, so the first experience is content, not a login wall.
Filters that remember. Filter state is kept on the device between visits, and non-search results are cached in the browser for 24 hours, so revisiting a filter is instant. Cards show skeletons while loading and the feed scrolls infinitely.
Plain building blocks. The interface is plain HTML, CSS and ES modules without a framework, so the design system is written in plain CSS rather than in a component library.
A catalogue of tens of thousands of texts is useless if people cannot narrow it quickly. I designed one filter interaction, Apply and Reset with removable chips, built it first for the Posts feed, and then reused it deliberately on Subscriptions and Paragraph filtering.
When each selection immediately re-queries the catalogue, people see the list flicker and jump while they are still choosing. They also cannot tell what is currently active once the panel closes. Three screens in the app had the same need, and three different filter designs would have meant three things to learn.
Texi is built for long-form text: books, study notes and articles of any length, with no images to carry the page. If reading is not comfortable, nothing else matters. This case study covers the reading experience and the type system underneath it.
Plain text offers no bold headings, no layout and no images, so spacing, size and typeface do all the work. Users also read in many scripts and directions, and different scripts need different size and line height to feel the same. A single reading setting would be wrong for most people.
Most of an app is not its big screens; it is the hundred small moments in between: confirming, waiting, leaving, picking. I replaced one-off solutions with a few patterns used everywhere, so the app feels like it was made by one hand.
Confirmations were built as plain alert dialogs, long actions finished with no clear sign of success, and leaving an editor offered a different set of buttons each time. Individually fine, together they made the app feel inconsistent.
Accessibility in Texi is not a checklist at the end. It is a small set of rules built into the components, so a new screen is accessible unless someone goes out of their way to break it.
Users choose their own colours, read in either direction and may use a screen reader. With so many themes, user-chosen card colours and languages, checking every combination by hand is impossible. The design had to guarantee the result.
| Need | Rule in the system | Result |
|---|---|---|
| Readable colour | Auto-contrast fallback with a fixed floor | Any user colour stays legible |
| Screen readers | Description on every icon-only control | Nothing left unnamed |
Texi has a published code: no likes, no comments, no view counters, no follower counts, no ranking, no ratings, no suggestions, no referral rewards, no keyword tracking, no trending lists and no images. For a designer these are not restrictions to work around. They are the brief.
Most apps use social proof, rankings and recommendations to guide attention. Texi's position is that these distort what people read and write: a like makes a reader biased before reading, and a view counter pushes a writer toward what is popular. Without them, the interface has to help people find and enjoy texts honestly.
| Rule | Reasoning behind it | What the interface does instead |
|---|---|---|
| No likes, ratings, rankings | They create bias before reading | Cards show only title, author and summary |
| No trending, no suggestions | They favour some texts over others and need behaviour tracking | The feed order is a seeded random order that stays stable across pages, so every text has an equal chance |
| No tracking | Readers are not data objects | Filter choices and caches stay on the device |
| No referral rewards | Sharing should come from wanting to share | Invites are a card the person designs, not a points scheme |
| No images | Attention should stay on the written word | Hierarchy comes from type and colour only |
Case study 01 is about the engine that sits underneath. This one is about the four pages built on top of it. Each page lets a person dress a piece of their own text, and each one has a different job: a book's cover, a quote to share, a public profile, and an invitation sent to a friend.
If every page were the same picker wrapped around the same box, a cover, a quote, a profile and an invitation would all look alike, even though people use them for different reasons. The brief I set was two-sided: the controls stay identical on every page, so nothing new has to be learned, while each page's content and hierarchy fit its own job.
| Page | What it holds | Its job | Design decision |
|---|---|---|---|
| Cover | A title and an author | Gives a book its own look | The title leads. Colour, frame, pattern and background stay underneath it. |
| Quote | A quote and its source | The heart of Texi, made to be shared | The quote is the loudest thing on the card. Patterns stay low in contrast. |
| Profile | A name | A person's public identity | With no images in the product, identity is carried by colour, frame and type. |
| Invite Friends | One invitation line | A message sent to a friend | The sender designs the card. It replaces a points scheme: Texi has no referral rewards. |
A simplified illustration of the idea. The proportions and sample text here are illustrative, not production layouts.
Next: show each design in the place it will be seen, for example a cover inside the library list and an invitation as the friend receives it, so choices are judged in context.
The case studies above show outcomes. This section shows the thinking underneath them: how I frame a problem, how I choose between options, and when I reverse a decision.
Read the work people actually do: long books in many scripts and directions, quotes shared to friends, small phones in bright light.
Write the problem in one sentence with a constraint. "Four editors almost match" is a defined problem. "Improve customization" is not.
Explore several variations side by side before choosing, including ones I expect to reject.
Build it in real Compose and Material 3 so spacing, motion and touch targets are tested for real, not drawn.
Run it on two physically different phones. Keep what holds, revert what does not.
Problem. The Texi web app needed an Explore page where people could browse a very large library and narrow it down, on a wide screen, without the page turning into a settings form.
Options. I explored several layout variations (A to D) for the side columns and the filters, and compared them on three questions: does the library stay the hero, can filters be reached without scrolling, and does it follow Material 3 rather than fighting it?
Decision. I chose variation D, the rail-and-card layout built in case study 04. The rail keeps navigation quiet and always reachable. The floating card keeps filters in sight and uses the staged Apply / Reset pattern with removable chips that I had already proven on three Android screens.
Problem. Changing theme repainted every surface at once. On a phone in a dark room that reads as a flash, and it makes the whole product feel like it is glitching.
Solution. A freeze-frame crossfade: capture the live screen, swap the theme underneath, then fade the frozen image out. The user sees one smooth transition, and the app never shows half-themed content. Press the button to see the idea in miniature (it respects reduced-motion settings).
Colour changes underneath; the old frame fades away on top.
A shipped design that fails real use is information. Over three months I reversed or reworked at least eleven decisions. The pattern is the useful part:
Each change was triggered by a specific visual or usability problem and fixed within days, not quarters.
| Habit | Where it shows |
|---|---|
| Standard before clever | When a screen is hard to understand I remove it or replace it with a standard pattern, such as Material 3 components and safe system fonts. |
| Compare, then decide | Explore-page variation D: several options, one clear choice, the rest left alone. |
| Global by default | I describe text as right-to-left or left-to-right, never as one language's special case, and every rule is built for both. |
| Separate the layers | Layout, behaviour and theming are specified separately, so a change to one cannot quietly break another. |
| Decide, then write it down | Every decision is recorded with its reason, so the people I work with can follow the direction without me in the room. |
| Legibility over taste | Text that reads as too thin gets heavier, and contrast is enforced by rules, not judged by eye. |
I direct the visual design and UX in writing: precise prompts that state layout, hierarchy and Material 3 standards, which an AI coding assistant implements in Compose. I review every result on devices, correct it, and ship it. This keeps design decisions mine while moving fast. A separate technical co-founder owns the data layer, and we agree on every data-dependent design decision, such as filtering, labelling and personalization, together. I use AI as an ideation and iteration partner, never as a substitute for the decision.
A spec and a renderer scale; a catalogue of assets does not. That decision is behind both the engine and the theme generator.
Building in Compose removed the handoff gap. Many fixes took hours rather than sprints because design and implementation were the same loop.
Next: bring the same system to the Texi web app in Material 3, drawing from the same tokens as the Android app.
If a term or a decision on this page was unclear, it is probably answered here. Tap a question to open it.
Texi is a reading and writing app for plain text. It holds tens of thousands of free ebooks, lets people make quote cards from text they like, and has a reader built for long texts in any language. The feed has no images, no likes and no tracking, so the design (type, colour, spacing) has to carry all the personality.
Ten case studies about the visual design and user experience of Texi, plus a section on how I think and work. Each case study follows the same order: the problem, how I thought about it, the technical direction, the look and feel, and the measured outcome. The numbers come from the shipping Android app.
Texi lets people decorate four things: a book cover, a public profile, an invite card and a quote card. Each had its own editor, built separately. I noticed they all asked the same questions (colour, frame, pattern, background, font), so I replaced four editors with one shared engine. Now someone who learns to style one card can style any card.
It means the look is generated from a small set of settings instead of loaded from a pile of ready-made images. One short “spec” (colour, frame, pattern, background, texture, size, font) describes a design, and a renderer draws it. That is why a design can be saved and shared as one small object, and why it works in every theme.
The product’s position is that attention should stay on the written word. Without pictures, hierarchy has to come from type size, weight, spacing and colour. In this project that is treated as the brief, not as a limit to work around: if something can be a colour and a line, it is not an image.
A theme is a colour personality for the whole app. I grouped the 46 themes by how people describe their taste: Content (12, one colour and the app follows it), Duo-tone (11, two colours that belong together), Tri-tone (13, three colours, such as a flag or a season) and Monochromatic (10, one calm hue). Settings shows them as four short tabs instead of one list of 46.
Hand-edited palettes drift apart and are easy to get wrong. Each theme is stored as a few seed colours plus its paradigm. The full set of about 25 colour roles (button colour, card colour, text colour and so on) is generated when needed, in both light and dark, so every theme is built by the same rules.
HCT is a colour space where “tone” matches what the eye sees as light or dark. In HSL, two colours with the same lightness number can look very different in brightness. With HCT, a tone-40 amber and a tone-40 lavender look equally light, which makes readable contrast predictable across all 46 themes.
It is the WCAG AA minimum ratio between text colour and the colour behind it, so text stays readable. Because users can choose any card colour, I can’t hand-pick text colours. The app searches for a text colour (a binary search on lightness) until the ratio reaches 4.5:1, so any colour a user picks stays legible.
RTL means right-to-left: some scripts are written and read from right to left, so the whole screen has to be mirrored. Texi supports both RTL and LTR (left-to-right) texts side by side. A layout built for one language quietly assumes LTR, so back buttons, swipes and padding break for RTL readers unless the layout is built for both.
There are 22 languages, each with 835 translated strings, one help file per language and one layout system for all of them. “Verified” is a manual process: every main flow was launched in each RTL language, long labels were stress-tested, reading scripts were checked in the reader, and two physical phones were used. It is checked, not assumed.
“Start” and “end” flip automatically with the language, so padding, alignment and swipe direction mirror on their own. Directional icons (back, forward, chevron, send) use the framework’s auto-mirrored set, so none of them is flipped by hand. Icons that are not directional, like play or a clock, correctly stay as they are.
A third “Cancel” button made people hesitate about what would happen. With two choices the outcome is clear. This is one example of a small decision made once and reused across the app.
Surprise me randomises a design in one tap, so people who face a big grid of options can still get something nice. Each setting must never repeat its previous value. For colour, a shuffle-bag deals every colour once before any colour appears again, which avoids the feeling of getting the same teal repeatedly.
With tens of thousands of texts, reloading the list on every tap makes it flicker while someone is still choosing. Choices stay a draft until Apply is pressed, and what is applied then shows as removable chips above the results. People can always see what is active and remove it with one tap. The same pattern is used on three screens.
Texi’s published code leaves out likes, comments, view counters, follower counts, ranking, ratings, suggestions, referral rewards, keyword tracking, trending lists and images. The reasoning is that a like or a counter biases a reader before reading and pushes writers toward what is popular. Each rule became a design decision, shown in a table in case study 09.
The catalogue request carries a seed, so texts appear in a stable random order while scrolling. Every text gets an equal chance, and no one’s behaviour is used to reorder anything. Every card has the same shape and shows only title, author and summary.
For the Explore page I compared several layouts (A to D) for the side columns and picked D: a slim Material 3 navigation rail on the left and a single floating Filters card on the right. The library stays the biggest thing on the page, and the Filters card is the only raised element, so it reads as a tool. The web app itself is still in progress.
I work directly in Jetpack Compose with small, reviewable changes, so the design and the shipped product cannot drift apart. I write precise briefs about layout, hierarchy and Material 3 standards, an AI coding assistant implements them, and I review every result on real devices. AI is an ideation and iteration partner, not the decision-maker. A technical co-founder owns the data layer and we agree on data-dependent design decisions together.
At least eleven shipped designs were reversed or redone in three months, such as retuned palettes, replaced icons, removed gradient washes and a simplified font picker. Each change followed real use on real phones, so I treat a revert as the process working. The figures come from the shipping Android codebase, while the interactive demos on this page are simplified illustrations, not production values.
Philosophy asks what a tool is for and what it should refuse to do. For Texi that produced rules such as no likes, no rankings and no tracking. Psychology explains how people behave in front of a screen: too many choices cause hesitation, a list that reloads on every tap feels jumpy, and quick feedback feels like success. Empathy decides where to start, with the reader who is tired, in a hurry or reading in the other direction. Each of these ideas turns into a concrete decision in the case studies.
No. Texi began on Android, and the same system now extends to a wide-screen web app in Material 3, where navigation becomes a slim rail and filters float in one card. The approach does not depend on a device. Start with the person, derive the look from a small set of rules, and let the layout adapt to the screen in hand, whether that is a phone, a tablet, a desktop or something new.