npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@klyftig/missions

v0.3.1

Published

Klyftig alarm dismissal missions for Expo / React Native: registry, MissionRunner (chains), type picker + config editor, and the Math / Shake / Memory / Barcode / Typing / Squat / Steps / Photo / Maze screens. Opt-in entry @klyftig/missions/pushup: camera

Downloads

910

Readme

@klyftig/missions

The dismissal missions for Klyftig's alarm apps: the obstacle a user must clear before an alarm from @klyftig/alarm-core stops. Extracted from Sleepwise's src/missions/ (2026-09-15).

Nine built-in missions plus one opt-in (Push-ups, below), all self-contained screens with props { config, onComplete, onStuck? }: Math, Shake, Memory, Barcode (Sleepwise's free tier) · Typing, Squat, Steps, Photo, Maze. nfc exists in the data model but is not registered (needs react-native-nfc-manager + device validation). Pure game logic (mathProblems, shakeDetection, memorySequence, squatDetection, maze) is unit-tested; sensor/camera screens are not.

import { MissionRunner, MissionTypePicker, MissionConfigEditor, MissionGatingProvider } from '@klyftig/missions';

// Ringing screen: walk the alarm's ordered missions (Multiple Missions).
<MissionRunner missions={alarm.missions} onComplete={dismiss} />

// Edit screen: pick a type / edit its config.
<MissionGatingProvider isPremium={isPremium} requirePremium={(proceed) => requirePremium('premiumMission', proceed)}>
  <MissionConfigEditor config={m.config} onChange={...} />
</MissionGatingProvider>

Gating is per app. The package never imports an entitlement store: MissionGatingProvider supplies isPremium, requirePremium(proceed) and optionally isPremiumMission(type) (defaults to @klyftig/alarm-core's PREMIUM_MISSIONS). Without a provider every mission is selectable — the right default for tests, dev harnesses and apps that don't gate missions.

Adding a mission: write the screen, register it in registry.tsx, add its MissionType + MissionConfig + default in @klyftig/alarm-core (domain/mission.ts), give it a labels entry and its copy in strings.tsx, and give each app a config editor branch.

Copy is per app too. Every visible and accessibility string lives in strings.tsx (DEFAULT_MISSION_STRINGS, English). Apps pass overrides from their own i18n through MissionStringsProvider; sections merge one level deep, so a partial section keeps English for the keys it leaves out, and counters are functions of the count so the app's plural rules apply:

<MissionStringsProvider strings={{
  labels: { math: t('missions:labels.math') },
  shake: { toGo: (n) => t('missions:shake.toGo', { count: n }) },
}}>

Mission labels live only there (MissionDefinition has no label since 0.2.0). Without a provider every screen renders English.

PhotoCapture (shared by the Photo mission and reference registration) has a torch toggle left of the shutter; pass suggestTorch to highlight it (e.g. the app judged the last capture too dark). Strings: camera.torchOnA11y / camera.torchOffA11y.

Push-ups (opt-in, 0.3.0)

@klyftig/missions/pushup counts full push-ups with the front camera and an on-device pose model (MoveNet Lightning int8, 2.9 MB, shipped in assets/). The phone stands upright on the floor beside the user; a rep = shoulders sink to ≤ 55 % of their height above the wrists and come back, in a straight-legged plank, in 0.5–8 s (knee push-ups don't count). It is a separate entry so apps that don't offer it never bundle the camera / ML native modules. To offer it:

npm i react-native-vision-camera react-native-vision-camera-worklets react-native-worklets \
      react-native-fast-tflite react-native-nitro-modules react-native-nitro-image
// metro.config.js — the model is a bundled asset
config.resolver.assetExts.push('tflite');
// app.config.js — iOS: VisionCameraWorklets needs React-Core's header path
plugins: ['@klyftig/missions', ...]
import { registerMission } from '@klyftig/missions';
import { pushupMission } from '@klyftig/missions/pushup';
registerMission(pushupMission); // once, at app start — the pickers and the runner then offer it

Ways out, so nobody is trapped: if the phone can't run it (no front camera, the model won't load, frames unreadable) the mission fails open (onComplete); if the user is out of view for 90 s it calls the host's onStuck (MissionRunner passes it through) — the host decides what that costs; without one it keeps waiting. Nothing is recorded. The pure parts (stepCounter, readPose, crop maths) are exported from the same entry; the counter's tuning and evaluation live in ~/Code/pushup-spike.

Gotchas: the Android emulator can't read camera frames (Nitro HardwareBuffer lock fails) and the iOS simulator has no camera — test on a phone. The camera uses orientationSource="interface" (a missing accelerometer makes 'device' throw).

Peer deps

@klyftig/alarm-core, @klyftig/mobile-ui (design tokens), expo-camera (Barcode/Photo), expo-sensors (Shake/Squat/Steps), expo-haptics, @expo/vector-icons. Optional (push-ups only): the six packages above + @expo/config-plugins (for app.plugin.js).

npm test             # 108 tests
npm run typecheck
npm run pack-local