Release notes

What we shipped, and when.

This page is generated directly from the project's CHANGELOG.md on every deploy. It is the same file we read internally — no marketing layer in between.

Changelog

All notable changes to Audris are documented here. The format follows Keep a Changelog and the project adheres to Semantic Versioning once tagged releases begin at v0.1.0.

This file covers both the mobile app (Android + iOS) and the public marketing site. Entries that apply only to one are tagged [app] or [site]; everything else applies to the project as a whole.

[Unreleased]

Added

  • [a11y] Accessibility hooks library at src/lib/accessibility.tsuseHighContrast() (iOS AccessibilityInfo.isHighTextContrastEnabled), useScreenReader() (live subscription), useFontScale(cap?), named FONT_SCALE_CAPS (reader 1.3 / chrome 1.6 / caption 1.4 / display 1.5). 9 unit tests.
  • [a11y] A11y polish pass across 30 files in app/ and src/components/ — every interactive element now has accessibilityLabel + accessibilityRole + accessibilityState + accessibilityHint where ambiguous. Tap targets audited for ≥48 dp with explicit hitSlop where needed. Waveform exposes role="adjustable" with ±15s seek via accessibilityActions. Mascot announces as "Audris, your narrator. Currently <state>." HighlightedText makes each sentence its own accessible button with onAccessibilityTap → seek. Speed slider, segmented controls (theme/font/sleep-timer/highlight-color/pause-profile) all role="radio" with state.checked. Live-regions for error toasts. Reduce-motion compliance audited and added where missing.
  • [native] Native code review pass across all 19 Kotlin + Swift files — 14 bugs fixed including: (1) PlayerService.kt cold-start ANR — startForegroundService requires startForeground within 5s on Android O+; now publishes notification in onCreate/onStartCommand; (2) PlayerController was missing fun interface modifier — SAM-lambda wouldn't have compiled; (3) iOS AudrisTtsModule.swift Constants was eager dict form — engine constant always read "supertonic" even after OnCreate flipped to apple-speech; switched to closure form; (4) iOS error-code parity — NSError(code: Int)Exception(name: "E_…") so JS sees consistent string code; (5) loadPlan timeout in module facade; (6) AudrisOcr.swift guard-let-self left Promise pending; (7) AudioPlayer.swift init/deinit + setSpeed/setVoice now main-thread wrapped (AVAudioEngine, MPRemoteCommandCenter, varispeedNode.rate are main-thread-only); (8) AudioPlayer rendered.count race with non-MainActor; (9) coroutine scope leaks in AudrisTtsModule.kt + AudrisPdfModule.kt (now cancelled in OnDestroy); (10) bundleOf ByteArray case; (11) onError chunkIndex sentinel parity. Two real concerns documented inline as REVIEW(charles): LookaheadBuffer.kt::nextChunk seek-during-playback race, AudrisPdfModule.kt::onPage.buffer JS-side Uint8Array-vs-ArrayBuffer type ambiguity. Binary format byte-by-byte parity confirmed across BinaryEncoder.kt / BinaryEncoder.swift / packages/extractor-decode/index.ts.
  • [docs] Architecture documentation at docs/architecture.md — engineer-facing system overview of every layer (app, components, store, services, native modules, pure-TS domain, decoder, persistence, marketing site, testing). ASCII diagrams per layer, the bridging decision explained, the flush-to-SQLite pattern, the amplitude SharedValue contract, the "where to put your next commit" cheat-sheet.
  • [docs] Native modules integration guide at docs/native-modules.md — recipes for adding methods + events to the three local Expo Modules (audris-pdf, audris-tts, audris-ocr), the binary buffer format byte-by-byte, EAS Build validation cycle, common gotchas (Kotlin 2.x, ProGuard for ONNX, onnxruntime-objc version pinning, --legacy-peer-deps, content URIs on Android, foreground service type, headless-modules rule), and the documented fallback path "if ONNX-on-iOS doesn't work."
  • [perf] Performance benchmark scaffolding at __tests__/perf/ — pure-TS benchmark runner (benchmark.ts) exposing benchmark(name, fn, { runs, warmup, setup, teardown }) returning min/max/mean/median/p95/p99 stats. Analyzer + formatter benchmarks against a 50-page synthetic document (analyzer.bench.test.ts, p95 budgets <500 ms / <100 ms / <600 ms). Decoder benchmarks against a 100-page synthetic input with UTF-8 mixed-script content (decoder.bench.test.ts, p95 budgets <50 ms / <25 ms). README documents what's measured today, what's deferred until real devices (time-to-first-audio, memory under playback, battery, model download), and the Phase 4 device-side plan.
  • [perf] npm run benchmark script — runs the perf suite (separate from npm run test because benchmark timings are non-deterministic; CI continues to run the regular test suite on every push).
  • [corpus] 30-PDF test corpus harness__tests__/fixtures/corpus/ with 12 synthetic fixtures spanning business proposals, research papers, contracts, code-heavy technical docs, and scanned-document edge cases. Corpus-evaluation test runs the analyzer + formatter against every fixture and snapshots role assignments + pause counts. +37 tests; total now 141/141 passing.
  • [site] Cornerstone blog post #4 — "How to listen to research papers on your phone." Academic-angle long-form covering why papers are hard for TTS, what structure-aware reading does for them, and a commute workflow.
  • [site] Cornerstone blog post #5 — "What your PDF reader sends to the cloud." Privacy-investigation post comparing cloud-TTS vs on-device architectures across Speechify, NaturalReader, Voice Aloud Reader, @Voice, Voice Dream Reader, and Audris, based on each app's public documentation.
  • [site] Cornerstone blog post #6 — "The best offline PDF-to-speech apps in 2026." Honest ranked listicle comparing Voice Aloud Reader, Voice Dream Reader, Speechify offline mode, NaturalReader offline tier, Audris, and Adobe Acrobat's built-in Read Out Loud across on-device fidelity, structure handling, privacy stance, and value.
  • [site] Cornerstone blog post #7 — "Why your TTS app reads section headers like body text (and how to fix it)." Educational long-form on the flat-text problem, what PDF metadata actually encodes, and the cognitive-load argument for structural pauses in audio.
  • [site] Cornerstone blog post #8 — "How we built Audris: a 6-month indie engineering retrospective." Build-in-public engineering retrospective covering the 13-day spike, architecture decisions that worked, decisions we got wrong, the numbers, and lessons for solo developers.
  • [site] Public /changelog page rendering this file at https://audris.app/changelog, linked from the footer.
  • [deploy] nginx vhost config at marketing-site/deploy/nginx-audris.conf — long-cache fingerprinted assets, short-cache HTML, full security header set (HSTS preload, nosniff, strict-origin-when-cross-origin, restrictive Permissions-Policy), www → bare redirect, custom 404, Cloudflare real-IP trust.
  • [deploy] Deploy script at marketing-site/deploy/deploy.sh — git-state check, build, scp, remote nginx -t && reload, curl smoke test, --dry-run flag, color-coded output, idempotent.
  • [deploy] Deployment README at marketing-site/deploy/README.md — first-time setup checklist, day-to-day workflow, rollback procedure, troubleshooting, co-tenant safety reminder.
  • [player] Player integration polish — real Mascot + ParticleField + sheet components wired in; sleep timer + bookmark-at-current end-to-end; amplitude SharedValue piped from tts.onAmplitude into both Mascot and ParticleField; skip-direction tilt; getCurrentSegment() / getCurrentSection() selectors on playerStore.
  • [ci] GitHub Actions CI workflow at .github/workflows/ci.yml — runs typecheck + the full vitest suite on every push to main and every PR. Node 20, npm cache, 10-minute timeout, concurrency cancellation.
  • [ci] Marketing-site build workflow at .github/workflows/marketing-site.yml — paths-filtered to marketing-site/**, builds the Astro site and uploads dist/ as a 7-day artifact for PR review.
  • [ci] Expo prebuild verification workflow at .github/workflows/expo-prebuild.yml — paths-filtered to native-affecting changes, runs expo prebuild --no-install --platform android and asserts the AndroidManifest contains the app.audris.tts.PlayerService entry. Catches withAudris config-plugin breakage early.
  • [docs] Top-level README.md — public-facing project overview, quickstart, project structure, tech stack, architecture diagram, dev workflow, testing, build/submit, contributing, acknowledgements. Voice-compliant with MARKETING §3.3.
  • [docs] MIT LICENSE — code under MIT; brand assets (name, mascot, icon, tagline, audio) explicitly reserved as © 2026 Charles Magno.
  • [ci] Issue + PR templates.github/PULL_REQUEST_TEMPLATE.md with the pre-merge handoff checklist; .github/ISSUE_TEMPLATE/bug_report.md with privacy reminder ("do not paste document content"); .github/ISSUE_TEMPLATE/feature_request.md with the counter-positioning reminder; .github/ISSUE_TEMPLATE/config.yml disables blank issues and routes to [email protected] + the marketing site.
  • [ci] Dependabot config at .github/dependabot.yml — weekly npm updates for the app and the marketing site (5 PRs/week cap each), monthly GitHub Actions updates, Charles auto-assigned as reviewer.

Changed

  • Nothing yet.

Fixed

  • Nothing yet.

Removed

  • Nothing yet.

Foundation

The pre-changelog baseline as of project kickoff.

Added

  • [app] Initial scaffold — Expo SDK 53 + expo-router v4 + TypeScript strict.
  • [app] Design system — Tamagui (chosen over NativeWind), Reanimated 3, Moti, Skia 1.5, Rive mascot via rive-react-native.
  • [app] Three in-repo Expo Modulesaudris-pdf (PdfBox-Android / PDFKit text extraction), audris-tts (Supertonic 3 via ONNX Runtime, with Apple Speech framework as the iOS fallback), audris-ocr (scanned-PDF OCR for the paid tier).
  • [app] Pure-TypeScript pipeline — PDF decoder, structure analyzer (font/color/position heuristics → SegmentRole tree), speech formatter (SpeechPlan with PCM silence + Supertonic expression tags).
  • [app] State and storage — Zustand 5, TanStack Query 5, MMKV, Drizzle + expo-sqlite.
  • [app] Native audio — MediaSession (Android), MPRemoteCommandCenter (iOS), CarPlay + Android Auto wiring planned for V1.
  • [site] Static Astro 5 marketing site at audris.app with hero, pricing, blog, press kit, privacy, terms, and support pages.
  • [site] Three cornerstone blog posts — "How Audris reads documents like a human" (the structure-aware pipeline), "Why Audris doesn't have a free trial" (anti-subscription philosophy), and "Speechify vs NaturalReader vs Audris: an honest comparison."

This will be versioned at v0.1.0 once we have a buildable preview release that runs end-to-end on real hardware (Phase 0 milestone, see plan).