Jamorham
Nightscout용 xDrip+ 버전
‘보통’ 수준의 AQI가 어느 날은 나쁘게, 다음 날은 괜찮게 변동할 수 있음
A “moderate” AQI can floor you one day and be fine the next. Breathing Index splits the AQI into the measurements it hides — including tree, grass, and weed pollen by plant — learns your triggers from
건강TypeScript · HTMLGitHub @DrewHoo온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기A personal air quality index: learns your triggers from your own breathing logs and shows what those logs expect from air like today's, on a four-level scale from 1 (Easy) to 4 (Dangerous).
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A personal air quality PWA. Live at breathingindex.com.
Twenty-two real entries from my own diary, in Hamden, on the New Haven monitor. The dashed line on each row is my easy level rather than the EPA's, because there are enough logs now to have one. Ozone came out a trigger; dry air and the pollens have so far not.README 전문 보기 ↗A personal air quality PWA. Live at breathingindex.com.
I’ve always struggled to correlate the published air quality index with my personal ability to breathe. It’s no fun being gaslit by a “moderate” AQI of 70 that some days is fine to breathe and somedays is cripplingly bad. The AQI is doesn't take into account how the combination of pollutants affects breathing, but your lungs sure do! So this app helps you create your own BQI (Breathing Quality Index) by recording how you feel about your breathing alongside a vector of all available measures, helping you map how your lungs are affected by different pollutants like ozone, smoke, pollen, dust, mold, etc, many of which are lumped into broad-based categories by AQI that, again, your lungs don't consider whilst breathing.
Instead of a uselessly granular 1-500 AQI index, your BQI has four ratings:
Each log entry is a 1–4 rating plus the full exposure vector at log time. A good entry is tolerance evidence for everything in that entry's measured air; a bad entry with several elevated variables produces an ambiguous candidate set, which the model keeps as-is until later entries confirm one candidate or exonerate another. The full model, with worked examples, is in docs/trigger-model.md; product spec and milestones are in SPEC.md.
Official composite indices (US AQI, EU EAQI) are captured on each log entry for possible later comparison, but never appear in the UI and are never used by inference.
TypeScript, React, Vite, TanStack Router (file-based routes), vite-plugin-pwa. The inference engine is a pure module at src/engine/ with no UI dependencies; its contract is the fixture suite at tests/fixtures/trigger-cases.json (16 cases, 39 assertions, run with vitest).
source: 'airnow'; otherwise they stay a comparison strip and the model drives.dry_spore_index, a count of the five weather conditions that put dry-weather spores in the air (specs/28-mold.md).All fetching is client-side; there is no backend. Logs live in localStorage — export and import are in Settings. Pollen keeps a small history there too: the measured feed serves today forward, and grass is graded over the trailing three days (docs/trigger-model.md), so the app writes each day down as it passes — capped, per coarse grid cell, and never the forecast days that arrive with it — instead of asking for a past nobody publishes. Smoke keeps the same kind of memory for the same reason, by the hour rather than the day.
Freshness comes from the payload's own newest hour rather than from when the response arrived: the service worker serves Open-Meteo network-first with a six-hour cache, so a cache hit is indistinguishable from a live fetch at arrival time. With no readings at all the quick log still works — the rating saves at once and picks up the exposure vector for its hour from Open-Meteo's three-day history on the next successful fetch. Until it does, the entry stays out of inference.
Temperatures display in °F for browsers whose locale resolves to a Fahrenheit region and °C everywhere else, overridable in Settings. Stored exposures are always metric, so the setting relabels the display and never rewrites logged history.
The palette follows prefers-color-scheme, with no manual toggle: a 4 AM breathing check should not be a flashlight to the face, and the four severity colours are re-pointed rather than inverted so the quiet end of the ramp stays quiet on a dark ground. Every screenshot in this README is the dark palette at phone size; Settings and the first-run screen are in docs/img/ too.
Analytics is Mixpanel, lazy-loaded, pseudonymous (a device ID, not an account) and content-free: events record that a screen was viewed or an entry saved, never what was rated, tagged, noted, or measured, and IP geolocation is off. Turn it off entirely in Settings. Fonts are self-hosted, so the app makes no third-party request for chrome either.
public/privacy.html and public/terms.html are prerendered documents served straight off disk at /privacy and /terms — no bundle, no router, and excluded from the service worker's navigation fallback. The privacy page enumerates every event and property the app sends; it is a contract, so any change to a track() call site belongs in the same commit as the change to that page.
npm install
npm run dev # local dev server
npm test # breakpoint-derivation check + engine fixture suite (vitest)
npm run build # vite build + typecheck
Deploys to GitHub Pages via Actions on every push to main. To redeploy without a new commit — or when an Actions incident swallows the push trigger — dispatch it manually:
gh workflow run deploy.yml