Features Platforms Privacy Support Get the App
Swift 5.9 SwiftUI SwiftData Apple Intelligence Zero Dependencies

01 Overview & Philosophy

Nummeric is built entirely on Apple's first-party frameworks with zero external dependencies. No CocoaPods, no SPM packages, no Carthage. Every line of code is either written in-house or provided by Apple's SDKs.

This isn't an arbitrary constraint. It's a deliberate architectural decision that enables:

  • Day-zero OS adoption — No waiting for third-party libraries to support new OS releases
  • Binary size control — No unused framework code bundled into the app
  • Security auditing — The entire dependency graph is Apple's responsibility
  • Reproducible builds — No network fetches during build, no version resolution conflicts
  • Privacy guarantees — No third-party SDK can phone home because none exist

Expression evaluation uses JavaScriptCore via an Objective-C exception bridge rather than any third-party math parsing library. This provides a battle-tested expression evaluator that's already on every Apple device.

Tech Stack at a Glance

LayerTechnology
LanguageSwift 5.9 with strict concurrency
UISwiftUI (100% declarative)
PersistenceSwiftData with schema versioning
SyncCloudKit via SwiftData automatic mirroring
AIFoundationModels (on-device LLM)
Math EngineJavaScriptCore + ObjC bridge
Build SystemXcodeGen (project.yml)
CI/CDGitHub Actions (macOS 15)
ConcurrencySwift Structured Concurrency (async/await)

02 Platform Targets

Nummeric ships as 5 distinct targets compiled from a shared model/utility layer, each tailored to its platform's interaction paradigm.

Deployment Targets
📱
iPhone / iPad
iOS 17.0+
💻
Mac (Native)
macOS 14.0+
Apple Watch
watchOS 10.0+
🥽
Vision Pro
visionOS 1.0+
🧩
Extensions
Widget, Keyboard, iMessage

All targets share the same bundle identifier (com.arix.calculator) enabling Universal Purchase — one purchase unlocks the app across all Apple platforms.

Code Sharing Strategy

Rather than using a Swift Package or framework target, Nummeric includes shared source files directly in each platform target via XcodeGen's sources paths. The Mac and visionOS targets include Arix/Models/ and Arix/Utilities/ with platform-specific file excludes. Mac provides compatibility stubs in ArixMac/Compat/ for iOS-only APIs like haptics and camera scanning.

03 Architecture Pattern

Nummeric uses an Observable Model with Environment Injection pattern — a lightweight MVVM variant that leverages Swift 5.9's Observation framework without a separate ViewModel layer.

Layer Architecture
View Layer SwiftUI Views — declarative, no business logic
State Layer @Observable models injected via Environment
Logic Layer Pure engines (enum/struct) — evaluators, parsers, solvers
Data Layer SwiftData models, UserDefaults, App Group shared state
Platform Layer CloudKit, JavaScriptCore, VisionKit, Speech, FoundationModels

Key Principles

  • No ViewModels. @Observable classes (e.g., CalculatorEngine, ThemeManager, ConverterEngine) are injected directly into the SwiftUI environment. Views read them via @Environment(CalculatorEngine.self).
  • Pure logic engines are stateless. Evaluators, parsers, and solvers are enum or struct types with static methods. No instance state, no side effects, fully testable.
  • Strict @MainActor isolation. All observable models are @MainActor-annotated. Background work uses Task.detached with structured concurrency. The project compiles with SWIFT_STRICT_CONCURRENCY: complete.
  • Singletons for cross-cutting concerns. Services like CurrencyRates.shared, HapticManager.shared, and AuthenticationManager.shared use the singleton pattern for app-wide state.
// App entry point — models created and injected into environment @main struct NummericApp: App { @State private var engine = CalculatorEngine() @State private var theme = ThemeManager() @State private var converter = ConverterEngine() var body: some Scene { WindowGroup { ContentView() .environment(engine) .environment(theme) .environment(converter) .modelContainer(container) } } }
// Observable model — @MainActor, automatic SwiftUI integration @Observable @MainActor final class CalculatorEngine { var display: String = "0" var expression: String = "" var memory: [Double] = [] var angleUnit: AngleUnit = .degrees func evaluate() { let result = ExpressionEvaluator.evaluate(expression) display = Formatter.format(result) } }

04 Feature Modules

Features are organized by domain in the Views/ directory. Each feature is a self-contained SwiftUI view backed by either an @Observable engine or inline state.

Feature Map

Calculator

Scientific, expression editing, history, memory, paper tape, RPN mode

Graphing

2D/3D plotting, multi-equation, trace mode, table of values, audio trace

Step Solver

AI-powered + local fallback, algebra/calculus/trig, verification

Notebook

Soulver-style live lines, named variables, handwriting canvas, export

Unit Converter

All SI categories, live currency rates, instant swap, search

214 Calculators

Declarative spec system, one generic view, formula steps, geometry diagrams

Matrix Algebra

Operations, determinants, inverses, step-by-step solutions

Programmer Mode

Hex/oct/bin, bitwise ops, number base explorer

Statistics

Data tables, visualizations, descriptive stats, distributions

AI Chat

On-device LLM, tool use, math context, streaming responses

Camera Scan

VisionKit DataScanner, receipt OCR, equation recognition

Voice Input

Speech recognition, NL math interpretation, on-device processing

Tab Management (iPhone)

All 10 primary tabs remain instantiated simultaneously in a ZStack with opacity(0) and allowsHitTesting(false) for hidden tabs. This preserves transient state (scroll position, partial input, graph zoom level) at negligible render cost since SwiftUI skips layout for invisible views. iPad uses a NavigationSplitView sidebar instead.

05 Data & Persistence

Nummeric uses SwiftData (Apple's Swift-native successor to CoreData) for all persistent storage, with schema versioning prepared for future migrations.

Persistent Models

ModelPurposeKey Fields
CalculationRecordFull calculation historyexpression, result, timestamp, title, isBookmarked
NotebookDocumentMulti-document math notebookstitle, body, createdAt, modifiedAt
ScratchpadSlotSaved intermediate valueslabel, value, createdAt, sortOrder
// Schema versioning — ready for future migrations enum NummericSchemaV1: VersionedSchema { static var versionIdentifier = Schema.Version(1, 0, 0) static var models: [any PersistentModel.Type] = [ CalculationRecord.self, NotebookDocument.self, ScratchpadSlot.self ] } enum NummericMigrationPlan: SchemaMigrationPlan { static var schemas: [any VersionedSchema.Type] = [NummericSchemaV1.self] static var stages: [MigrationStage] = [] }

Storage Tiers

The ModelContainer is constructed with a three-tier fallback strategy:

CloudKit-backed (if sync enabled)
Local SQLite (default)
In-memory (fallback on error)

Additional Storage

  • UserDefaults — All preferences (angle unit, decimal places, theme, calculator mode) via @AppStorage
  • App Group (group.com.arix.calculator) — SharedCalcState for widget extension communication. Uses a single Codable snapshot to prevent torn reads during concurrent widget refreshes
  • Custom file type.arixnote (UTI: com.arix.calculator.note) with Transferable conformance for notebook sharing

06 iCloud Sync

Cross-device synchronization is opt-in (disabled by default for privacy) and uses SwiftData's automatic CloudKit mirroring.

Sync Flow
SwiftData Model
ModelConfiguration(.cloudKitDatabase: .automatic)
iCloud.com.arix.calculator
  • Opt-in toggle in Settings: iCloudSyncEnabled (defaults to false)
  • Container: iCloud.com.arix.calculator
  • visionOS excluded — spatial sessions are ephemeral; local-only store
  • Failure handling: Logs error, sets cloudKitFailed flag for UI warning, falls back to local store
  • Handoff via NSUserActivity (com.arix.calculator.currentCalculation) — continue a calculation on another device

07 Extension Ecosystem

Nummeric ships with 3 app extensions, bringing the calculator to every surface of the OS.

Extensions & Entry Points

W Widget Extension

Home screen, Lock screen, Control Center, and Dynamic Island Live Activities. Interactive calculation, conversion, graphing widgets. iOS 18+ Control Center buttons.

K Keyboard Extension

Custom system keyboard with a mini calculator. UIKit-based UIInputViewController. Standalone engine (no shared code with main app). 5-row grid with Insert button to paste result.

M iMessage Extension

MSMessagesAppViewController with SwiftUI hosting. Compact/expanded modes. Composes rich message bubbles with expression/result. Recipients can continue the calculation.

A App Intents

Siri Shortcuts integration and Spotlight indexing. Calculate, convert, and save to scratchpad via voice or Shortcuts automation.

Widget Types

WidgetTypeDescription
CalcWidgetStaticShows last calculation result
QuickCalcWidgetInteractivePerform calculations directly from home screen
ConversionWidgetStaticLast unit conversion
GraphWidgetStaticMini graph preview
NotebookWidgetStaticNotebook content preview
NummericLiveActivityLive ActivityDynamic Island + Lock Screen progress
CalculatorControlWidgetControliOS 18 Control Center button

08 Apple Intelligence

All AI features run entirely on-device using Apple's FoundationModels framework (iOS 26+ / macOS 26+). No data ever leaves the device. When the device doesn't support AI, every feature has a deterministic fallback.

AI Integration Pipeline
1 Availability checkSystemLanguageModel.default.availability verified at launch
2 Session management — Long-lived LanguageModelSession instances keyed by topic (capped at 8)
3 Structured output@Generable structs for typed responses (e.g., ParsedMath, BillScan)
4 Streamingsession.streamResponse(to:) for real-time token output in chat UI
5 Tool use — AI can call CalculateTool, ConvertTool, SaveToScratchpadTool, SearchHistoryTool

AI-Powered Features

FeatureAI ImplementationFallback
Natural language math@Generable struct ParsedMathRegex-based NLMathInterpreter
Calculation explanationsStreaming LLM responseheuristicExplanation() pattern matching
Ask Nummeric chatMulti-turn session with toolsNot available (feature hidden)
Step-by-step solverStepSolver with structured stepsLocalStepSolver (linear, quadratic, systems)
Notebook title suggestionContent summarizationFirst line of body text
Bill scanning@Generable struct BillScanVisionKit text extraction only
// AI Tool conformance — the model can invoke real calculator functions struct CalculateTool: Tool { let name = "calculate" let description = "Evaluate a mathematical expression" @Generable struct Input { let expression: String } func call(input: Input) async throws -> String { let result = ExpressionEvaluator.evaluate(input.expression) return Formatter.format(result) } }

09 Calculator Engine

The core expression evaluator uses JavaScriptCore via an Objective-C exception bridge. This provides a battle-tested math evaluation runtime without any third-party dependency.

Expression Evaluation Flow
User Input
MathExpressionParser
JSContext (serial queue)
Result + Formatting

Why JavaScriptCore?

  • Already on every Apple device — zero additional binary size
  • Handles operator precedence, parentheses, floating point correctly
  • Nummeric extends it with custom functions (sin, cos, log, factorial, etc.) injected into the JS context
  • The ObjC bridge (ObjCExceptionBridge) wraps evaluation in @try/@catch since Swift cannot catch ObjC exceptions from JSContext

Thread Safety

A shared JSContext instance is protected by a serial DispatchQueue. All evaluations are synchronized to prevent concurrent access, which JSContext does not support.

// ObjC Exception Bridge — catches JSContext exceptions safely @objc class ObjCExceptionBridge: NSObject { @objc static func tryEvaluate( _ expression: String, in context: JSContext ) -> JSValue? { // @try { return [context evaluateScript:expression]; } // @catch (NSException *e) { return nil; } } }

Supporting Engines

EnginePurposeType
CalculatorEngineMain state management@Observable class
RPNEngineReverse Polish Notation stack@Observable class
ExpressionEvaluatorJS evaluation wrapperenum (static)
MathExpressionParserToken parsing / validationenum (static)
GraphEvaluatorFunction plottingenum (static)
GraphAnalysisRoots, extrema, inflectionsenum (static)
MatrixEngineMatrix operations@Observable class
NumberBaseEngineHex/oct/bin conversion@Observable class
LocalStepSolverDeterministic equation solvingenum (static)
StatisticsEngineDescriptive stats / distributions@Observable class

10 Calculator Registry

The 214 specialty calculators (BMI, mortgage, compound interest, pace, etc.) are expressed entirely as data — no per-calculator view code. A single generic FormulaCalculatorView renders any calculator from its spec.

Declarative Calculator System
CalculatorRegistry
CalcSpec (inputs + outputs + formula)
FormulaCalculatorView
Result + Steps + Diagram

Spec Structure

// Each calculator is pure data — no custom view code needed struct CalcSpec { let id: String let name: String let category: CalcCategory // fitness, finance, engineering... let inputs: [CalcInput] // labeled fields with units & validation let outputs: [CalcOutput] // computed results with formatting let formula: ([Double]) -> [Double] // pure computation let steps: [FormulaStep] // step-by-step explanation let diagram: DiagramType? // optional geometry diagram }

Why this matters: Adding a new calculator requires writing ~15 lines of data declaration. No new views, no new files, no new tests. The generic view and evaluation pipeline handle everything. This is how 214 calculators ship in a single-person project without technical debt.

Categories

Calculators span fitness, health, finance, engineering, cooking, geometry, physics, chemistry, and everyday utilities. Each shows the formula, step-by-step derivation, and (where applicable) a vector-drawn geometry diagram.

11 Testing & CI

Nummeric has a comprehensive test suite with 31 unit test files and 24 UI test files, run on every push via GitHub Actions.

Unit Tests (31 files)

Engine Tests

CalculatorEngine, RPNEngine, Converter, Matrix, NumberBase, Statistics

Parser/Evaluator

ExpressionEvaluator, MathExpressionParser, LineParser

Solver Tests

LocalStepSolver, RichFormulaStep, StepDiffEngine

Graph Tests

GraphAnalysis, GraphEvaluator

Integration

Intents, ThemeManager, CurrencyRates, SpotlightIndexer

Special

FuzzTests, PerformanceTests, SnapshotTests, AppleIntelligenceMath

UI Tests (24 files)

Per-feature smoke tests for every major tab, accessibility tests, error recovery, theme switching, tab persistence, and hamburger menu navigation.

CI Pipeline

GitHub Actions Pipeline (macOS 15)
XcodeGen
SwiftLint
Static Analysis
Build
Tests (ASan + UBSan)
Coverage Check (40% min)
TSan Job (separate)
Artifact Upload
  • Sanitizers: Address Sanitizer (ASan) + Undefined Behavior Sanitizer (UBSan) in main test run; Thread Sanitizer (TSan) in separate job (incompatible with ASan)
  • Simulators: iPhone 16 Pro + iPad Pro 13-inch matrix
  • Coverage gate: 40% minimum (warns below 60%)
  • Caching: DerivedData + Homebrew dependencies cached between runs
  • Linting: SwiftLint with relaxed rules for math code (no line_length, identifier_name, file_length enforcement)

12 Design Decisions

Key architectural choices and the reasoning behind them.

Zero External Dependencies

Every third-party dependency is a liability: it can break on OS updates, introduce security vulnerabilities, add unused code weight, or be abandoned. By building on Apple's stack exclusively, Nummeric can adopt new OS features on day one and guarantees that no third-party code ever touches user data.

ObjC Exception Bridge for JSContext

JavaScript evaluation can throw ObjC exceptions that Swift cannot catch. Rather than using a third-party expression parser, Nummeric wraps JSContext.evaluateScript() in an Objective-C @try/@catch block. This provides safe, battle-tested math evaluation with zero additional binary size.

Declarative Calculator Specs

With 214 specialty calculators, a naive approach would require 214 view files. Instead, each calculator is a pure data declaration consumed by one generic view. Adding a calculator is a 15-line struct. This keeps the codebase linear rather than exponential.

ZStack Tab Preservation

SwiftUI's TabView destroys and recreates tab content on switch. Nummeric keeps all tabs alive in a ZStack with visibility toggles, preserving partial input, scroll position, and graph zoom across tab switches. The render cost is negligible since invisible views skip layout.

Atomic Widget State

SharedCalcState writes a single Codable snapshot to the App Group container instead of using separate UserDefaults keys. This prevents torn reads when the widget timeline refreshes concurrently with a main app write.

AI with Deterministic Fallbacks

Every Apple Intelligence feature has a working non-AI path. The step solver includes a full local algebraic solver (linear, quadratic, systems of equations). Natural language parsing falls back to regex. This ensures the app is fully functional on devices that don't support Apple Intelligence.

Theme System with Thread Safety

Seven visual themes (paper, pop, cyberpunk, terminal, brutalist, memphis, blueprint) with per-theme background patterns rendered via drawingGroup() for Metal-accelerated composition. Theme state resolution uses OSAllocatedUnfairLock for thread safety across concurrent view renders.

Audio Graph Accessibility

AudioTraceEngine sonifies graph curves using stereo panning (x-position maps to left/right), timbre shift (positive/negative y values), and click sounds at intersections (roots). This makes graphing accessible to visually impaired users.

Strict Concurrency

The project compiles with SWIFT_STRICT_CONCURRENCY: complete — the strictest setting. All @Observable models are @MainActor. Background work uses structured concurrency (Task.detached, async/await). No data races are possible at compile time.

+ Project Structure

Nummeric/ ├── Arix/ # Main iOS app source │ ├── Models/ # Pure-logic engines, parsers, data models │ ├── Utilities/ # Services (AI, haptics, currency, auth) │ ├── Views/ # SwiftUI views organized by feature │ └── Intents/ # App Intents / Siri Shortcuts ├── ArixMac/ # Native macOS app │ ├── Compat/ # Platform stubs for iOS-only APIs │ └── Views/ # Mac-specific views ├── ArixVision/ # visionOS spatial app ├── ArixWatch/ # watchOS standalone app ├── ArixWidget/ # WidgetKit (home, lock, control, live activity) ├── ArixKeyboard/ # Custom keyboard extension (UIKit) ├── ArixMessages/ # iMessage app extension ├── ArixTests/ # 31 unit test files + snapshots ├── ArixUITests/ # 24 UI test files + helpers ├── scripts/ # Build scripts ├── docs/ # Documentation ├── site/ # Marketing website ├── .github/workflows/ # CI pipeline └── project.yml # XcodeGen project definition