A drawing app for kids with a parent-lock feature. Kids can draw freely; parents can lock the screen behind a PIN so the child can't navigate away.
| Runtime | Expo SDK 57 / React Native 0.86 |
| Language | TypeScript (strict) |
| Navigation | expo-router (file-based) |
| Drawing — Android | react-native-svg 15 (MIT, builds from source — see docs/PACKAGING.md) |
| Drawing — Web | HTML5 <canvas> (platform file: DrawingCanvas.web.tsx) |
| Touch input | react-native-gesture-handler v2 (Gesture API) |
| PIN storage | AsyncStorage + expo-crypto SHA-256 |
| Android nav bar | expo-navigation-bar (hidden in lock mode) |
| Screen wake | expo-keep-awake (screen stays on while drawing) |
app/
_layout.tsx Root layout — GestureHandlerRootView, no headers
index.tsx Draw screen (home); redirects to /pin-setup on first launch
pin-setup.tsx 4-digit PIN creation (enter → confirm)
settings.tsx Change PIN (requires current PIN)
components/
DrawingCanvas.tsx Native: react-native-svg <Path> + RNGH PanGesture
DrawingCanvas.web.tsx Web: HTML5 <canvas>
ColorPicker.tsx 8-swatch color picker
Toolbar.tsx Colors + S/M/L brush + eraser + undo + clear
PinPad.tsx 4-digit numeric pad with shake animation
hooks/
usePin.ts Save / verify / clear hashed PIN
useLockState.ts locked boolean + lock / unlock
utils/
hash.ts expo-crypto SHA-256 wrapper
plugins/
withReleaseSigning.js Release keystore instead of the debug key
withOfflineReleaseManifest.js Drops INTERNET from release builds
android/ Committed, not generated at build time
fastlane/metadata/ Store listing, read by fdroid update
fdroid/com.kidsdoodle.app.yml Licence/categories/links for the repo index
- Node.js 18+
- Expo Go on Android, or a local debug build (
npm run android) - For a release build: JDK 17 + the Android SDK, or just push a tag and let CI do it
git clone <repo>
cd kids-doodle
npm installnpx expo startScan the QR code with Expo Go on Android.
Note:
expo-navigation-bar(hiding the system nav bar while locked) only works in a native build (npm run android). All other features work in Expo Go.
npx expo start --androidnpx expo start --webThe web version uses an HTML5 canvas rather than react-native-svg. Full feature parity except the nav-bar hiding (web has no system nav bar).
The app is not on Google Play. Each v* tag builds three signed APKs, one per
CPU architecture, and attaches them to a GitHub Release; a self-hosted F-Droid
repo at lbellows/fdroid — shared with
the sibling BracketUp app — indexes those same files so any F-Droid client can
install and update from it. Obtainium works
against the Releases page with no setup on our side. See
docs/PACKAGING.md for the release process, the keystore
setup, and the repo URL and fingerprint.
The released APK requests no Android permission at all. It has no network access, no ads, no analytics and no third-party SDKs.
The app is not built with EAS or shipped to Google Play, so there is no
eas.json. Release APKs are built from the committed android/ project:
cd android && ./gradlew assembleRelease # debug-signed, like F-Droid's buildPushing a v* tag builds and signs one in CI and attaches it to a GitHub
Release. See docs/PACKAGING.md.
| Feature | Android | Web |
|---|---|---|
| Freehand drawing | SVG paths | HTML5 canvas |
| 8 preset colors | ✓ | ✓ |
| Brush sizes (S / M / L) | ✓ | ✓ |
| Eraser | ✓ | ✓ |
| Undo last stroke | ✓ | ✓ |
| Clear canvas | ✓ | ✓ |
| Keep screen awake | ✓ | n/a |
| Lock screen (PIN overlay) | ✓ | ✓ |
| Wrong-PIN shake + vibrate | ✓ | shake only |
| Hide system nav bar | ✓ | n/a |
| Block hardware back button | ✓ | n/a |
| First-launch PIN setup | ✓ | ✓ |
| Change PIN (settings) | ✓ | ✓ |
- App opens → no PIN found in AsyncStorage → redirect to PIN Setup
- Enter a 4-digit PIN, then confirm it
- PIN is SHA-256 hashed and saved to AsyncStorage
- Returned to the draw screen
- Tap 🔒 (top-right) → semi-transparent overlay covers the canvas
- Android: system nav bar hides, hardware back button is blocked
- Enter the correct 4-digit PIN → overlay dismisses
- Wrong PIN → shake animation + vibration, try again
- Expo Go + nav bar:
expo-navigation-baris a native module; the lock-screen nav-bar-hiding feature requires a native build via EAS (previewordevelopmentprofile). - No Skia: the native canvas uses
react-native-svg, not@shopify/react-native-skia. Skia downloads prebuilt static libraries from GitHub Releases at install time, which breaks this repo's no-prebuilt-binaries rule. Don't reintroduce it. See docs/PACKAGING.md. - Metro platform resolution:
metro.config.jsexplicitly adds'web'toresolver.platforms; without this, Metro ignores.web.tsxfiles even when bundling for web. android/is committed: regenerate it withnpx expo prebuild --platform androidafter changingapp.jsonorplugins/, and commit the diff. CI fails if it is out of sync.
