InkPond (墨池) is a native iOS/iPadOS editor for Typst, with live preview and PDF export powered by a Rust FFI bridge.
- English (current)
- 简体中文: README.zh-CN.md
| Action | Command / Link |
|---|---|
| Download | App Store |
| Join TestFlight beta | testflight.apple.com/join/w5jmkR2T |
| Build Rust FFI | cd rust-ffi && ./build-ios.sh |
| Simulator debug build | xcodebuild -project InkPond.xcodeproj -scheme InkPond -configuration Debug -destination 'generic/platform=iOS Simulator' build |
| Export options file | release/ExportOptions.plist |
Editor
- Parser-backed Typst syntax highlighting with themed tokens, rainbow bracket coloring, and bracket mismatch detection
- Auto-pairing for
{}[]()""$$with smart type-over, auto-delete, and auto-indent - Code completion for Typst functions (~150), keywords,
#importpackage specs, font families, labels, references, and image paths - Snippets library with custom templates and
$0cursor placeholders - Find and replace (system
UIFindInteraction) - Line number gutter with error line highlighting
- Keyboard accessory bar with quick-insert buttons
Preview & Compile
- Typst
0.15.0compilation through a Rust FFI bridge - Live SVG/WKWebView preview with debounced recompilation (350ms)
- Bidirectional editor-to-preview sync via source maps
@previewpackage downloads cached on device, plus local package resolution- Document statistics (pages, words/tokens, characters; CJK-aware)
- Error banner with source location links
- Full-screen slideshow mode
- Parser-backed outline view for heading navigation
- Compiled preview cache for faster reopen and rebuild cycles
Project Management
- Multi-file projects with customizable entry file
- Project file browser with .typ, image, and font sections
- Image import from Photos, clipboard (including HTML paste), and remote URLs
- Per-project, app-wide, and system font resolution for explicit Typst font declarations
- Optional iCloud project sync with separate app font, local package, and snippet sync controls
- Local Typst package manager for folders and
.zip/.tar/.tar.gz/.tgzarchives - ZIP project import and export
- PDF and source (.typ) export
UI/UX
- Adaptive layout: split view on iPad, tabbed on iPhone
- Separate app appearance controls plus three editor themes: Mocha (dark), Latte (light), System (adaptive) — based on Catppuccin
- Onboarding flow for new users
- Editor position resumption across launches
- Full VoiceOver and accessibility support
- Localized in English, Simplified Chinese, Traditional Chinese (HK/TW)
- Settings for iCloud, app fonts, local packages, keyboard shortcuts, and compile/package/system-font caches
- iOS 26 keyboard glass and visual enhancements where available, with iOS 17-compatible fallbacks
- macOS with Xcode 26.3+
- iOS/iPadOS deployment target: 17.0 (app target)
- Rust toolchain (
rustup,cargo) for buildingtypst_ios.xcframework
- Clone repo:
git clone <your-fork-or-origin-url> cd InkPond
- Make sure the native toolchain is ready:
If any of these fail, install Xcode command line tools and the Rust toolchain before continuing.
xcode-select -p cargo --version rustup show
- Rebuild the Rust FFI framework after Rust changes:
This updates the committed
cd rust-ffi ./build-ios.sh cd ..
Frameworks/typst_ios.xcframework. - Build and run in Xcode:
open InkPond.xcodeproj
# Simulator debug build
xcodebuild -project InkPond.xcodeproj -scheme InkPond -configuration Debug -destination 'generic/platform=iOS Simulator' build
# Device release archive
xcodebuild -project InkPond.xcodeproj -scheme InkPond -configuration Release -destination 'generic/platform=iOS' archive
# Unit tests
xcodebuild test -project InkPond.xcodeproj -scheme InkPond -only-testing:InkPondTests -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.5'
# UI tests
xcodebuild test -project InkPond.xcodeproj -scheme InkPond -only-testing:InkPondUITests -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.5'
# If your local simulator list differs, inspect available destinations first:
# xcodebuild -showdestinations -project InkPond.xcodeproj -scheme InkPondFrameworks/typst_ios.xcframeworkis generated byrust-ffi/build-ios.shand committed so Xcode Cloud can build without a Rust bootstrap step.rust-ffi/build-ios.shbuilds the three Rust slices in parallel by default and keepsrust-ffi/target/so Cargo can reuse compiled dependencies across rebuilds.- Set
RUST_FFI_PARALLEL_SLICES=0to build slices serially,CARGO_BUILD_JOBS=<n>to control jobs per slice, orCLEAN_RUST_TARGET=1to removerust-ffi/target/after packaging. - Rebuild and commit
Frameworks/typst_ios.xcframework/when Rust FFI output changes. - The Swift bridge passes font paths, the project root, an
@previewpackage cache, and the local package directory into Rust. - Re-run
rust-ffi/build-ios.shwhen:- updating Typst / Rust dependencies
- changing
rust-ffi/src/lib.rs
- If Xcode shows
Typst compiler library not linked, the xcframework is missing, stale, or was built before switching branches. Re-run the build script and rebuild the app.
Current pinned Typst version: 0.15.0 (see rust-ffi/Cargo.toml).
Typical flow:
# 1) Archive
xcodebuild -project InkPond.xcodeproj -scheme InkPond -configuration Release -destination 'generic/platform=iOS' -archivePath /private/tmp/InkPond.xcarchive archive
# 2) Export IPA (using your ExportOptions.plist)
xcodebuild -exportArchive -archivePath /private/tmp/InkPond.xcarchive -exportPath /private/tmp/InkPond-export -exportOptionsPlist release/ExportOptions.plist
# 3) Upload (InkPond app id)
asc --profile default builds upload --app 6760032537 --ipa /private/tmp/InkPond-export/InkPond.ipa --output tableAfter upload, wait for processing, then distribute build to TestFlight groups.
Public App Store listing: apps.apple.com/us/app/inkpond/id6760032537
InkPond/
├── InkPond/
│ ├── InkPondApp.swift # @main entry point, SwiftData ModelContainer
│ ├── ContentView.swift # NavigationStack project home, environment setup
│ ├── AppAppearanceManager.swift # App-wide light/dark/system appearance
│ ├── Models/
│ │ └── InkPondDocument.swift # @Model: document data + project config
│ ├── Editor/
│ │ ├── TypstTextView.swift # UITextView subclass (TextKit 1)
│ │ ├── SyntaxHighlighter.swift # Typst token styling + rainbow brackets
│ │ ├── CompletionEngine.swift # Context-aware code completion
│ │ ├── AutoPairEngine.swift # Bracket/quote auto-pairing
│ │ ├── SyncCoordinator.swift # Bidirectional editor↔preview sync
│ │ ├── EditorTheme.swift # Mocha/Latte/System theme definitions
│ │ ├── ThemeManager.swift # Theme persistence (UserDefaults)
│ │ ├── Snippet*.swift # Snippet model, library, and store
│ │ ├── HighlightScheduler.swift # Debounced highlighting
│ │ ├── LineNumberGutterView.swift # Gutter with error markers
│ │ └── KeyboardAccessoryView.swift # Accessory bar (photo/snippet buttons)
│ ├── Compiler/
│ │ ├── TypstBridge.swift # Rust FFI wrapper (compile + source map)
│ │ ├── TypstCompiler.swift # Debounced SVG/PDF preview pipeline + cache
│ │ ├── SourceMap.swift # Line↔page bidirectional mapping
│ │ ├── ProjectFileManager.swift # Per-project file CRUD + validation
│ │ ├── FontManager.swift # Project/app font metadata + parsing helpers
│ │ ├── CompileFontResolver.swift # Font resolution and materialization planning
│ │ ├── CoreTextFontMaterializer.swift
│ │ │ # System font materialization cache for Typst
│ │ ├── LocalPackageStore.swift # Local Typst package catalog and imports
│ │ ├── PackageArchiveImporter.swift
│ │ │ # Package archive extraction
│ │ ├── ExportManager.swift # PDF/source/ZIP export (custom ZIP writer)
│ │ ├── ExportController.swift # Export UI state machine
│ │ ├── ZipImporter.swift # ZIP project import
│ │ ├── DirectoryMonitor.swift # DispatchSource file system watcher
│ │ └── *CacheStore.swift # Compiled preview + package caches
│ ├── Views/
│ │ ├── DocumentList/ # Document library, search, sort, rename
│ │ ├── DocumentEditor/ # Editor/preview split, file ops, images
│ │ │ └── OutlineView.swift # Heading outline navigation
│ │ ├── EditorView.swift # UIViewRepresentable for TypstTextView
│ │ ├── PreviewPane.swift # SVG/WKWebView live preview + stats + sync marker
│ │ ├── SlideshowView.swift # Full-screen SVG slideshow
│ │ ├── OnboardingView.swift # First-launch onboarding
│ │ ├── SnippetBrowserSheet.swift # Snippet library browser
│ │ ├── ProjectFileBrowserSheet.swift
│ │ ├── ProjectSettingsSheet.swift
│ │ └── Settings/ # iCloud, appearance, editor font, packages, fonts, caches, shortcuts
│ ├── Localization/ # L10n.swift lookup helpers
│ ├── Resources/Localization/ # Localizable.xcstrings (en, zh-Hans, zh-Hant-HK, zh-Hant-TW)
│ ├── Storage/
│ │ ├── StorageManager.swift # Local/iCloud mode and migration
│ │ ├── Cloud*.swift # iCloud coordination, availability, sync monitor
│ │ └── AppFontLibrary.swift # App-wide font import tracking
│ ├── Shared/UI/ # UIKit/SwiftUI bridges, haptics, a11y
│ ├── Support/
│ │ ├── AppIdentity.swift # Bundle/app group/iCloud identifiers
│ │ └── InteractionSupport.swift # Haptics and accessibility announcements
│ └── Bridging/ # typst_ffi.h bridging header
├── rust-ffi/
│ ├── src/lib.rs # Rust Typst wrapper
│ ├── Cargo.toml # Rust dependencies (Typst engine)
│ └── build-ios.sh # XCFramework build (device + sim)
├── Frameworks/
│ └── typst_ios.xcframework/ # Committed Typst FFI artifact
├── release/
│ └── ExportOptions.plist
└── InkPond.xcodeproj
Typst compiler library not linked:- Run
cd rust-ffi && ./build-ios.shand rebuild the app. - If the script fails immediately, check
cargo --version,rustup show, andxcode-select -p. - If the script succeeds but Xcode still fails to link, clean the build folder and rerun the app build.
- Run
- Simulator link errors about
typst_iosarchitecture:- Rebuild xcframework; the script generates
arm64 + x86_64simulator slices.
- Rebuild xcframework; the script generates
- TestFlight upload succeeded but not distributable yet:
- Build is still processing in App Store Connect.
@previewpackage import fails:- Check network access, then clear the package cache from Settings and recompile.
- iCloud files appear missing or not downloaded:
- Open the Files app, go to iCloud Drive, and keep the InkPond folder downloaded before reopening the project.
- Typst - core typesetting engine used for rendering and PDF generation (Apache 2.0)
- Catppuccin - color system used by the editor themes (MIT)
- swift-bridge - inspiration and reference for Swift/Rust interop patterns (MIT or Apache-2.0)
- Thanks to everyone at Donut for support and inspiration.