Kuji is an interactive decision‑making app that helps you make choices through a fun, lottery‑style experience. Create multiple decision lists for different aspects of your life, customize probabilities for each option, scratch to reveal your fate, and reflect on outcomes in a built‑in journal. Designed to run as a Progressive Web App and as a native Android APK via Capacitor.
- Multiple decision lists per context (food, workouts, chores, etc.)
- Weighted options with customizable probabilities
- Scratch‑card reveal experience and animations
- Decision history with weekly trends and charts
- Reflection/decision journal to capture thoughts and outcomes
- Theme selection (light/dark/system) with persistence
- Fully responsive PWA with offline support
- Framework: Next.js 14 (App Router)
- Language: TypeScript
- Styling: Tailwind CSS 4.1 + custom animations
- UI Primitives: Radix UI + custom components
- State: Zustand + Immer
- PWA: @ducanh2912/next-pwa (Workbox under the hood)
- Mobile: Capacitor 7 (Android APK)
- Node.js 18+
- pnpm (recommended) or npm
- Java JDK 17 (for Android build)
- Android SDK/Platform Tools (for APK/emulator)
# Install dependencies
pnpm install
# Start dev server
pnpm devnpm run deploy:androidThis will:
- Build the Next.js app (static export with PWA)
- Sync Capacitor
- Build both release and debug APKs
- Output artifacts
- kuji-release.apk (project root)
- kuji-debug.apk (project root)
# 1) Initial Android setup (adds platform + keystore if needed)
npm run apk:setup
# 2) Build PWA and sync Capacitor
npm run pwa:build
# 3a) Build release APK
npm run android:build && npm run apk:copy
# 3b) Or build debug APK
npm run android:build-debug && npm run apk:copy-debugAPK build outputs (from Gradle) also live under:
android/app/build/outputs/apk/{release,debug}/
| Script | Description |
|---|---|
dev |
Start Next.js dev server |
build |
Next.js build |
start |
Start Next.js production server |
typecheck |
TypeScript typecheck |
pwa:build |
Build PWA (static export) and cap sync |
android:setup |
Add Android platform to Capacitor |
android:sync |
Sync Android project |
android:clean |
Clean Android build cache |
android:build |
Build release APK via Gradle |
android:build-debug |
Build debug APK via Gradle |
android:run |
Run app on device/emulator |
apk:setup |
Android setup + keystore creation |
apk:build |
Build PWA + release APK + copy artifact |
apk:build-debug |
Build PWA + debug APK + copy artifact |
apk:full-build |
Release + debug builds in sequence |
build:compat |
Build flow focused on WebView‑compat testing |
webview:check |
Inspect connected device/emulator WebView version |
deploy:android |
Full pipeline to produce APKs |
{
"name": "Kuji - Random Decision Maker",
"short_name": "Kuji",
"description": "Interactive decision-making app that helps you make choices through a fun, lottery-style experience. Create multiple decision lists, customize probabilities, and reveal your fate by scratching cards.",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#000000",
"orientation": "portrait",
"scope": "/",
"icons": [
{ "src": "/favicon.ico", "type": "image/x-icon", "sizes": "16x16 32x32" },
{ "src": "/icon-192.png", "type": "image/png", "sizes": "192x192" },
{ "src": "/icon-512.png", "type": "image/png", "sizes": "512x512" },
{ "src": "/icon-192-maskable.png", "type": "image/png", "sizes": "192x192", "purpose": "maskable" },
{ "src": "/icon-512-maskable.png", "type": "image/png", "sizes": "512x512", "purpose": "maskable" }
]
}import withPWAInit from '@ducanh2912/next-pwa'
const withPWA = withPWAInit({
dest: 'public',
cacheOnFrontEndNav: true,
aggressiveFrontEndNavCaching: true,
reloadOnOnline: true,
swcMinify: true,
disable:
process.env.DISABLE_PWA === 'true' ||
process.env.NODE_ENV === 'development' ||
process.env.CAPACITOR_BUILD === 'true',
workboxOptions: {
disableDevLogs: true
}
})
export default withPWA({
images: { unoptimized: true },
output: 'export',
trailingSlash: true,
distDir: 'out'
})import type { CapacitorConfig } from '@capacitor/cli'
const config: CapacitorConfig = {
appId: 'com.kuji.app',
appName: 'Kuji',
webDir: 'out',
server: {
androidScheme: 'https',
cleartext: true,
allowNavigation: ['*']
},
android: {
allowMixedContent: true,
captureInput: true,
webContentsDebuggingEnabled: true,
includePlugins: [],
backgroundColor: '#1A1A1E',
overrideUserAgent:
'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36',
appendUserAgent: 'KujiApp/1.0.0'
}
}
export default configRunning web content inside Android System WebView can behave differently from Chrome on device. Kuji includes utilities and styles to improve rendering on older WebViews.
-
Runtime detection and body flags via
src/lib/webview-compat.ts:- Adds classes like:
webview,webview-old,webview-no-modern-css,webview-no-backdrop-filter,webview-no-oklch,webview-chrome-<major> - Fallbacks for glass/blur, neon glows, gradients when features are missing
- MutationObserver to re-apply fallbacks on dynamic content
- Adds classes like:
-
Dedicated styles for degraded environments:
src/styles/webview-compat-enhanced.css
-
Build/test helpers:
npm run build:compat— builds PWA and a debug APK to test WebView fallbacksnpm run webview:check— prints the connected device/emulator WebView version and tips
- Older WebView versions (< Chrome 120) not fully supporting modern CSS
backdrop-filter(and-webkit-backdrop-filter) rendering inconsistencies- OKLCH color values not supported — need hex/rgba fallbacks
- Occasional gradient banding and lack of
gapsupport in flex/grid on very old engines - Emulators without Google Play images ship with outdated WebView providers
- Prefer emulators with Google Play system images and keep Android System WebView up to date (120+)
- If layouts look off, run
npm run webview:checkand consider switching the WebView provider to Chrome - Use the provided fallback classes in custom components as needed
For a deeper dive, see: WebView Compatibility Guide
- Visit the deployed site in a modern browser
- Use “Add to Home Screen” to install as a standalone PWA
- Build using the steps above
- Install the resulting
kuji-release.apkorkuji-debug.apkon your device
- One codebase across web and mobile
- Offline‑first experience for quick, repeat use
- Fast iteration with web tooling; native feel via Capacitor shell
