
Oku is a React progressive web app (PWA) bootstrapped with Create React App. It is served as a client-side SPA โ the shell HTML includes a "You need to enable JavaScript to run this app" fallback confirming the CRA pattern. The viewport is locked (maximum-scale=1, user-scalable=no, viewport-fit=cover), signalling a mobile-first, app-like experience. Payments are handled via Paddle.
Oku uses a two-typeface system:
The pairing creates contrast between editorial warmth (Fabric Serif headlines) and functional clarity (Inter UI text). Base font size is 16px; the type scale follows a modular ratio roughly aligned to 12 / 14 / 16 / 20 / 24 / 32 / 48px steps.
Oku's palette is high-contrast and black-dominant. The marketing site and app shell use near-black backgrounds (#0A0A0A / #111111) with off-white text (#F5F5F5) for a premium, editorial feel that suits a book-culture product. Accent usage is intentionally minimal โ a muted warm-neutral or a single brand accent is used for interactive states. The overall mood is restrained, letting book cover art provide colour.
Spacing follows an 8px base grid. Common values: 4px (xs), 8px (sm), 16px (md), 24px (lg), 32px (xl), 48px (2xl), 64px (3xl). The bento-grid marketing layout uses 16โ20px gutters between cards. Component internal padding is typically 16px or 24px.
The marketing landing page uses a bento grid layout โ asymmetric modular cards showcasing app features (reading lists, collections, stats, social feed). The app itself is a mobile-first single-column layout with a bottom navigation bar. Max content width on desktop is approximately 1200px with centred alignment and generous horizontal padding (24โ40px).
/_ oku.club โ inferred CSS custom properties _/
/\* Source: visual analysis, Lapa Ninja metadata (Inter + Fabric Serif, black palette),
PWA shell inspection, and Fabric Serif foundry specs (Monokrom, 2020) \*/
:root {
/_ โโ Typography โโ _/
--font-sans: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--font-serif: 'Fabric Serif', Georgia, 'Times New Roman', serif;
--font-mono: ui-monospace, 'SFMono-Regular', Menlo, monospace;
--font-size-xs: 0.75rem; /_ 12px _/
--font-size-sm: 0.875rem; /_ 14px _/
--font-size-base: 1rem; /_ 16px _/
--font-size-lg: 1.25rem; /_ 20px _/
--font-size-xl: 1.5rem; /_ 24px _/
--font-size-2xl: 2rem; /_ 32px _/
--font-size-3xl: 3rem; /_ 48px _/
--font-weight-regular: 400;
--font-weight-medium: 500;
--font-weight-bold: 700;
--line-height-tight: 1.2;
--line-height-snug: 1.375;
--line-height-normal: 1.5;
--line-height-relaxed:1.625;
--letter-spacing-tight: -0.02em;
--letter-spacing-normal: 0em;
--letter-spacing-wide: 0.04em;
/_ โโ Colour โ Dark (default) โโ _/
--color-bg-primary: #0A0A0A;
--color-bg-secondary: #111111;
--color-bg-elevated: #1A1A1A;
--color-bg-overlay: #222222;
--color-text-primary: #F5F5F5;
--color-text-secondary: #A3A3A3;
--color-text-tertiary: #6B6B6B;
--color-text-disabled: #4A4A4A;
--color-text-inverse: #0A0A0A;
--color-border: #2A2A2A;
--color-border-subtle: #1E1E1E;
--color-border-strong: #3A3A3A;
--color-accent: #F5F5F5; /_ primary CTA โ white on black _/
--color-accent-hover: #E0E0E0;
--color-accent-muted: #2A2A2A;
--color-success: #4CAF50;
--color-warning: #FF9800;
--color-error: #EF5350;
/_ โโ Spacing (8px grid) โโ _/
--space-1: 0.25rem; /_ 4px _/
--space-2: 0.5rem; /_ 8px _/
--space-3: 0.75rem; /_ 12px _/
--space-4: 1rem; /_ 16px _/
--space-5: 1.25rem; /_ 20px _/
--space-6: 1.5rem; /_ 24px _/
--space-8: 2rem; /_ 32px _/
--space-10: 2.5rem; /_ 40px _/
--space-12: 3rem; /_ 48px _/
--space-16: 4rem; /_ 64px _/
--space-20: 5rem; /_ 80px _/
--space-24: 6rem; /_ 96px _/
/_ โโ Border Radius โโ _/
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-xl: 16px;
--radius-full: 9999px;
/_ โโ Shadows (minimal in dark mode) โโ _/
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.5);
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.6);
/_ โโ Layout โโ _/
--container-max: 1200px;
--container-padding: 1.5rem;
--bento-gap: 1rem; /_ 16px card gutter _/
--nav-height: 56px;
}
/_ โโ Light mode overrides (if supported) โโ _/
@media (prefers-color-scheme: light) {
:root {
--color-bg-primary: #FFFFFF;
--color-bg-secondary: #F5F5F5;
--color-bg-elevated: #FAFAFA;
--color-bg-overlay: #EFEFEF;
--color-text-primary: #0A0A0A;
--color-text-secondary: #4A4A4A;
--color-text-tertiary: #6B6B6B;
--color-text-disabled: #A3A3A3;
--color-text-inverse: #F5F5F5;
--color-border: #E0E0E0;
--color-border-subtle: #EFEFEF;
--color-border-strong: #CBCBCB;
--color-accent: #0A0A0A;
--color-accent-hover: #222222;
--color-accent-muted: #F0F0F0;
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.06);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.12);
}
}
| Token | Value | Usage |
|---|---|---|
--color-bg-primary | #0A0A0A | Page / app shell background |
--color-bg-secondary | #111111 | Card backgrounds, sidebars |
--color-bg-elevated | #1A1A1A | Modals, dropdowns, tooltips |
--color-text-primary | #F5F5F5 | Body copy, headings |
--color-text-secondary | #A3A3A3 | Subtext, metadata, placeholders |
--color-text-tertiary | #6B6B6B | Disabled labels, hints |
--color-border | #2A2A2A | Card borders, dividers |
--color-accent | #F5F5F5 | Primary CTA button fill |
--color-accent-hover | #E0E0E0 | CTA hover state |
--color-success | #4CAF50 | Success states, reading goal completion |
--color-error | #EF5350 | Error messages, destructive actions |
| Token | Value | Usage |
|---|---|---|
--space-1 | 4px | Icon gaps, micro nudges |
--space-2 | 8px | Inline spacing, tag padding |
--space-4 | 16px | Component internal padding, bento gutter |
--space-6 | 24px | Card padding, section spacing |
--space-8 | 32px | Between sections |
--space-12 | 48px | Large section gaps |
--space-16 | 64px | Hero / page-level vertical rhythm |
| Token | Value | Usage |
|---|---|---|
--font-sans | 'Inter', system-ui, sans-serif | UI text, labels, body copy, navigation |
--font-serif | 'Fabric Serif', Georgia, serif | Display headings, marketing headlines, editorial pull-quotes |
--font-size-sm | 14px | Captions, metadata, timestamps |
--font-size-base | 16px | Body text, form inputs |
--font-size-lg | 20px | Card titles, subheadings |
--font-size-xl | 24px | Section headings |
--font-size-2xl | 32px | Page-level headings |
--font-size-3xl | 48px | Hero display text (Fabric Serif) |
--font-weight-regular | 400 | Body text |
--font-weight-medium | 500 | Labels, navigation items |
--font-weight-bold | 700 | Headings, CTA text |
--line-height-normal | 1.5 | Body text default |
--line-height-tight | 1.2 | Display headings |
| Token | Value | Usage |
|---|---|---|
--radius-sm | 4px | Tags, chips, badges |
--radius-md | 8px | Buttons, input fields |
--radius-lg | 12px | Cards, bento grid tiles, modals |
--radius-xl | 16px | Large feature cards |
--radius-full | 9999px | Avatars, pill buttons, progress rings |
| Token | Value | Usage |
|---|---|---|
--shadow-sm | 0 1px 2px rgba(0,0,0,0.4) | Subtle elevation, hover states |
--shadow-md | 0 4px 12px rgba(0,0,0,0.5) | Floating cards, bottom nav |
--shadow-lg | 0 8px 24px rgba(0,0,0,0.6) | Modals, drawer overlays |
Framework & stack: Oku is a React PWA (Create React App pattern), confirmed by the JavaScript-required fallback, CRA-style static serving, and PWA meta tags (apple-mobile-web-app-capable, mobile-web-app-capable). The viewport is locked with user-scalable=no, maximum-scale=1, viewport-fit=cover, enforcing a native-app feel on mobile. Payments run through Paddle (confirmed by the founding team in Product Hunt comments).
Theme support: The site is natively dark โ the marketing page and app shell both default to a black-dominant palette. Light mode support is likely provided via a prefers-color-scheme media query or a user toggle, though the primary brand expression is dark. No explicit color-scheme meta tag was observed in the HTML shell, suggesting the dark theme is baked into the CSS rather than declared at the document level.
Data confidence:
Notable design patterns:


.webp)


.webp)













SaaSFrame subscriptions are sold on Lemon Squeezy, a secured online selling platform for creators.
SaaSFrame gets updated all the time! Every new update and version will immediately be made available to all SaaSFrame users.
You can generate an invoice on your Lemon Squeezy portal once you purchased SaaSFrame. You will find the link in the order confirmation email.
You can cancel your membership subscription at any moment on your profile page.โ
If you're not satisfied, you can ask for a refund within 7 days. Just send me an email at antoine[at]unmake[dot]io
You can send me an email at antoine[at]unmake[dot]io, I'll be happy to help with any questions.