Guidelines for AI coding agents working on this codebase. Read this before making any changes.
SnipKey is a native iOS app (SwiftUI + SwiftData) that lets users create, organize, and quickly access text snippets, URLs, images, and PDFs via a custom keyboard extension.
| Version | 5.5 (main app), 5.0 (keyboard extension) |
| Bundle ID | jrtv-projects.SnipKey |
| Min Deployment | iOS 17.0 (base), iOS 26.0 in latest build configs |
| Architecture | MVVM with SwiftData |
| Sync | iCloud via CloudKit |
| Monetization | Free app with optional tips via RevenueCat |
| Privacy | No analytics, no tracking, no third-party data sharing |
Targets:
SnipKey— Main iOS applicationSnipKeyboard— Custom keyboard extension (jrtv-projects.SnipKey.SnipKeyboard)
Shared infrastructure:
- App Group:
group.snipkey(shared data between app and keyboard extension) - iCloud Container:
iCloud.SnipKeyCloud
Open SnipKey.xcodeproj, select the SnipKey scheme, pick a simulator or device, and press Cmd + R.
# Build the main app (debug)
xcodebuild -project SnipKey.xcodeproj -scheme SnipKey -configuration Debug build
# Build for a specific simulator
xcodebuild -project SnipKey.xcodeproj -scheme SnipKey \
-destination 'platform=iOS Simulator,name=iPhone 16' build
# Clean build
xcodebuild -project SnipKey.xcodeproj -scheme SnipKey clean buildThe keyboard extension must be enabled manually:
- Go to Settings > General > Keyboard > Keyboards > Add New Keyboard
- Select SnipKey
- (Optional) Enable Allow Full Access for image/PDF clipboard operations
No tests currently exist. Test targets (SnipKeyTests, SnipKeyUITests) are defined in the Xcode scheme but contain no test files. Adding tests is a welcome contribution.
# Run all tests (when they exist)
xcodebuild test -project SnipKey.xcodeproj -scheme SnipKey \
-destination 'platform=iOS Simulator,name=iPhone 16'
# Run a single test class
xcodebuild test -project SnipKey.xcodeproj -scheme SnipKey \
-destination 'platform=iOS Simulator,name=iPhone 16' \
-only-testing:SnipKeyTests/TestClassName
# Run a single test method
xcodebuild test -project SnipKey.xcodeproj -scheme SnipKey \
-destination 'platform=iOS Simulator,name=iPhone 16' \
-only-testing:SnipKeyTests/TestClassName/testMethodNameSnipKey/
├── SnipKeyApp.swift # @main app entry point
├── ContentView.swift # [DEAD CODE] Default Xcode template, unused
├── SnipKeyDataManager.swift # Shared SwiftData ModelContainer factory
├── SnipKey.entitlements # App entitlements (iCloud, App Groups)
├── Info.plist # App configuration
├── IBMPlexMono-*.ttf # Custom fonts (Regular, Medium, SemiBold, Bold)
├── Assets.xcassets/ # App icons, images, SVGs, colors
│
├── Core/
│ └── Colors.swift # Color extensions (system colors + hex init)
│
├── Components/
│ ├── AboutApp.swift # Developer bio / about screen
│ ├── TipDevView.swift # Tip jar UI (RevenueCat products)
│ ├── TagColorPicker.swift # Color palette picker for tags
│ ├── TagColorIndicator.swift # Colored circle tag display
│ ├── MorphingSymbolView.swift # Animated SF Symbol transitions
│ ├── StaggeredImagesList.swift # Overlapping card-style media gallery
│ └── LoopVideoView.swift # Looping video player component
│
├── Helper/
│ ├── Biometrics.swift # FaceID / TouchID (LocalAuthentication)
│ ├── Keyboard.swift # Keyboard utilities (clipboard, extension detection)
│ ├── RevenueCatManager.swift # RevenueCat singleton (tip jar)
│ ├── AppIconProvider.swift # App icon name resolver
│ ├── Views.swift # View extensions (hideKeyboard, limitText, pressable)
│ └── Strings.swift # String extensions (HMAC, URL validation, attributed text)
│
├── Tips/
│ └── HomeTips.swift # TipKit definitions (3 tips)
│
└── Features/
├── Home/View/
│ ├── HomeView2.swift # PRIMARY home view (TabView: Snippets/Settings/Search)
│ ├── HomeView.swift # [LEGACY] NavigationSplitView home, unused
│ ├── HomeSnippetList.swift # Snippet list component
│ └── SearchView.swift # Full search view with tag browser
│
├── Snippets/
│ ├── SnippetModel.swift # SwiftData models: SnippetItem, SnipTag, SnippetFile
│ ├── SnippetViewModel.swift # Snippet CRUD + tag + file operations
│ └── Views/
│ ├── SnippetForm.swift # Create/edit form (single + bulk modes)
│ ├── SnippetViewDetail.swift # Snippet detail (with biometric lock)
│ ├── SnippetListItem.swift # List row + minimal keyboard grid item
│ ├── SnippetTagForm.swift # Tag selection + batch move
│ ├── EditTagView.swift # Edit tag sheet (name, icon, color, delete)
│ ├── TagsView.swift # Settings > Tags management list
│ ├── SnippetContentForm.swift # Dynamic content editor (text/URL/image/PDF)
│ ├── SnippetContentViewDisplay.swift # Content display renderer
│ ├── SnippetFilesView.swift # Image gallery (masonry grid)
│ ├── SnippetListEmpty.swift # Empty state with typewriter animation
│ ├── KeyboardStatusView.swift # Keyboard setup status indicator
│ └── ArrowSVG.swift # Decorative arrow shape
│
├── Settings/
│ ├── Model/SettingsModel.swift # SettingsModel (@Model) + enums
│ ├── ViewModel/SettingsViewModel.swift # Settings business logic
│ └── Views/SettingsView.swift # Full settings screen
│
├── Subscription/Views/
│ └── SubscriptionView.swift # Free app info screen (placeholder)
│
└── OnBoarding/
├── OnBoardingModel.swift # BoardingItem struct
├── Model/Page.swift # 5-page onboarding page definitions
└── Views/
├── OnBoardingView.swift # Feature list onboarding
├── OnboardingStepperView.swift # 5-step animated welcome walkthrough
├── WelcomeView.swift # Tab-style welcome cards
├── BoardingCardView.swift # Individual boarding card
├── Splashscreen.swift # Splash screen (1.2s)
└── KeyboardHelpGuideView.swift # 3-step keyboard setup guide
SnipKeyboard/ # Keyboard Extension Target
├── KeyboardViewController.swift # UIInputViewController + QWERTY state management
├── KeyboardView.swift # SwiftUI keyboard UI (snippet grid + QWERTY toggle)
├── SnipKeyboard.entitlements # Extension entitlements
├── Info.plist # Extension config (RequestsOpenAccess: true)
└── QWERTY/ # Full QWERTY keyboard implementation
├── KeyboardDimensions.swift # Responsive key measurements from screen width
├── QWERTYKeyboardState.swift # @Observable render state + plain input tracking
├── KeyboardActions.swift # textDocumentProxy closures via SwiftUI environment
├── QWERTYKeyboardLayout.swift # Static key definitions for letters/numbers/symbols
├── KeyButtonView.swift # Key rendering with UIKit KeyTouchArea (touch lifecycle)
├── KeyRowView.swift # HStack row with zero-dead-zone padding + probabilistic data
├── QWERTYKeyboardView.swift # Main keyboard view + toolbar + slash suggestions
├── KeyPopupView.swift # UIKit balloon popup for key press visual feedback
├── SlashCommandEngine.swift # Slash command tracker + state + fuzzy matching engine
├── PredictiveTextEngine.swift # Predictive text tracker + state + suggestion engine
├── BigramEngine.swift # Static English bigram frequency table (26x26)
├── DynamicHitResolver.swift # Probability-weighted key boundary resolver
└── ProbabilisticTouchContext.swift # Per-keystroke context for probabilistic touch targeting
@Model
final class SnippetItem {
var creationDate: Date?
var updatedDate: Date?
var id: String?
var title: String?
var content: String?
var isSecure: Bool = false
var lastTimeUsed: Date?
var usedCount: Int = 0
var type: SnipType? // .txt, .url, .file, .image
@Relationship(inverse: \SnipTag.snippets)
var customTag: SnipTag?
@Relationship(inverse: \SnippetFile.snippet)
var file: SnippetFile?
}@Model
final class SnipTag {
var creationDate: Date = Date.now
var name: String?
var imageTag: String? // SF Symbol name
var id: String?
var colorHex: String? // Hex color string, e.g. "#FF3B30"
var snippets: [SnippetItem]?
}@Model
final class SnippetFile {
var id: String?
var fileType: FileType? // .document, .image
var fileFormatType: String? // MIME type: "image/png", "image/jpeg", "application/pdf"
@Attribute(.externalStorage)
var fileData: Data? // Binary data stored externally by SwiftData
var snippet: [SnippetItem]?
}@Model
final class SettingsModel {
var settingsId: String = "SnipKey-Settings"
var afterPasteAction: KeyboardAfterPasteAction = .space
// Possible values: .rtrn, .space, .change, .changeReturn, .nothing
}enum SnipType: String, Codable {
case txt, url, file, image
}
enum FileType: String, Codable {
case document, image
}
enum KeyboardAfterPasteAction: String, Codable {
case rtrn, space, change, changeReturn, nothing
}SnipKeyDataManager creates a shared ModelContainer accessible to both the main app and the keyboard extension via the group.snipkey App Group. The schema includes SnippetItem.self and SettingsModel.self — SnipTag and SnippetFile are included automatically via relationships.
| Package | Version | Purpose |
|---|---|---|
| AlertToast | 1.3.9 | Toast / banner notifications |
| CloudKitSyncMonitor | 1.2.1 | iCloud sync status indicator |
| Pow | 1.0.3 | Animations (confetti, conditional effects) |
| RevenueCat | 5.4.0 | In-app purchase tips (tip jar only) |
| SwiftUIMasonry | main | Masonry grid layout (image gallery) |
| SymbolPicker | 1.5.2 | SF Symbol selection for tags |
All packages resolve automatically when opening the project in Xcode.
System frameworks first, then third-party packages:
import Foundation
import SwiftUI
import SwiftData
import TipKit
// Third-party
import AlertToast
import RevenueCat| Layer | Convention | Example |
|---|---|---|
| Model | SwiftData @Model classes in *Model.swift |
SnippetModel.swift |
| ViewModel | @Observable classes in *ViewModel.swift |
SnippetViewModel.swift |
| View | SwiftUI views, use @Query for data fetching |
SnippetForm.swift |
| Element | Convention | Example |
|---|---|---|
| Files | PascalCase | SnippetViewModel.swift |
| Types / Classes | PascalCase | SnippetItem, SnipType |
| Properties / Variables | camelCase | isSecure, customTag |
| Enums | PascalCase type, camelCase cases | SnipType.txt, FileType.document |
| @ViewBuilder functions | PascalCase + "View" suffix | ListItemsView(), AddSnippetButtonView() |
// User defaults persistence
@AppStorage("isOnboarding") var isOnboarding: Bool = true
// Environment for dependency injection
@Environment(\.modelContext) var modelContext
@Environment(SettingsViewModel.self) private var settingsViewModel
// SwiftData queries
@Query(sort: \SnippetItem.creationDate, order: .reverse) private var snippets: [SnippetItem]
// Shared managers as StateObject
@StateObject private var revenueCatManager = RevenueCatManager.sharedUse @ViewBuilder for reusable view components within a view:
@ViewBuilder
func ListItemsView() -> some View {
// View implementation
}
@ViewBuilder
func AddSnippetButtonView() -> some View {
// View implementation
}The app uses IBM Plex Mono. Always use these font names:
.font(.custom("IBMPlexMono-Regular", size: 12))
.font(.custom("IBMPlexMono-Medium", size: 14))
.font(.custom("IBMPlexMono-SemiBold", size: 15))
.font(.custom("IBMPlexMono-Bold", size: 16))Use custom Color extensions for system-adaptive colors:
Color.label // UIColor.label
Color.secondaryLabel // UIColor.secondaryLabel
Color.systemBackground // UIColor.systemBackground
Color.secondarySystemBackground // UIColor.secondarySystemBackground
Color.tertiarySystemBackground // UIColor.tertiarySystemBackgroundFor hex-based colors (used in tag colors):
Color(hex: "#FF3B30")Current pattern uses print statements and optional chaining:
do {
let snippets = try modelContext?.fetch(fetchDescriptor)
return snippets
} catch {
print("FAILED TO FETCH SNIPPETS")
return []
}For save operations:
try? self.modelContext?.save()User preferences stored via @AppStorage:
@AppStorage("showTipDev") var showTipDev: Bool = false
@AppStorage("isKeyboardShortcutEnabled") var isKeyboardShortcutEnabled: Bool = false
@AppStorage("isOnboarding") var isOnboarding: Bool = trueThe keyboard extension (SnipKeyboard target) is a UIInputViewController that hosts a SwiftUI view. It operates in two modes: QWERTY typing and snippet browsing, toggled via a button in the toolbar or the bottom-row snippet key.
KeyboardViewControllersubclassesUIInputViewControllerand owns:QWERTYKeyboardState(@Observable) — shared render state injected into SwiftUI environmentKeyboardActions(struct of closures) — wrapstextDocumentProxyoperations, passed via SwiftUI@EnvironmentKeyPopupView(UIKit) — singleton balloon popup added as a subview above the SwiftUI hosting controller- Explicit
NSLayoutConstraintfor keyboard height (no GeometryReader)
KeyboardViewExt(SwiftUI) conditionally rendersQWERTYKeyboardViewor the snippet grid based onqwertyState.showingSnippets- Text is inserted via
textDocumentProxy.insertText()— this bypasses paste restrictions - Images and PDFs are copied to
UIPasteboard.general(requires Full Access)
The QWERTY keyboard is built in SnipKeyboard/QWERTY/ with 13 files. Key architecture decisions:
State management:
QWERTYKeyboardState(@Observable) holds only view-affecting properties:currentPage,shiftState,returnKeyLabel,returnKeyIsProminent,appearanceMode,needsInputModeSwitchKey,showingSnippetsQWERTYInputTracking(plain class, NOT@Observable) holds internal tracking for auto-period detection and shift double-tap timing. Mutations here cause zero SwiftUI re-renders.- All
@Observablemutations fromKeyboardViewControlleruse equality guards (if value != newValue) to prevent unnecessary re-renders. viewWillLayoutSubviews()only callsupdateQWERTYState()when screen width changes;textDidChange()handles per-keystroke updates.
Touch handling:
- Character keys and the space bar use
KeyTouchArea— aUIViewRepresentablewrappingUIControlwith full touch lifecycle (touchDown/touchUpInside/touchUpOutside/touchCancel). - Character insertion fires on
.touchDown(not.touchUpInside) for ~30-80ms lower latency. KeyTouchArea.onTouchDownprovides both the touch X position and the control's actual frame in keyboard coordinates (viaUIEventparameter +convert(bounds, to: nil)). Character keys use the touch X for probabilistic hit resolution; the actual frame is used for popup positioning.KeyTouchAreaalso handles visual highlight viaUIControl.backgroundColorchanges — pure CALayer, no SwiftUI state.- On the letters page, character keys run
DynamicHitResolverinline on each touch-down (~100ns) to check if the touch should redirect to an adjacent key based on bigram probabilities. See Probabilistic Touch Targeting section below. - Special keys (shift, backspace, snippet toggle) use SwiftUI
Buttonfor long-press gesture support.
Key press visual feedback (balloon popup):
KeyPopupViewis a singleUIViewinstance reused for all keys. It contains aUILabel+CAShapeLayerdrawing a balloon shape with a downward-pointing tail.- Show/hide is done via
CALayerproperty changes (isHidden,frame,transform) — zero SwiftUI state mutations, zero layout passes. - Spring scale animation runs on the Core Animation render server, not the main thread.
- Character/digit/symbol keys get balloon popup + background highlight on press.
- Space bar gets background highlight only (no popup), and dismisses any active popup.
- Special keys (shift, backspace, return, etc.) have no visual feedback currently.
- Popup is positioned using the
UIControl's actual frame from UIKit layout (viaconvert(bounds, to: nil)), not duplicated arithmetic. This eliminates drift between SwiftUI layout and popup positioning.
The slash command system detects /query patterns during typing and shows matching snippet suggestions in the keyboard toolbar. It uses a two-phase evaluation design to avoid per-keystroke SwiftUI re-renders:
Phase 1 — Detection (UIKit side, per-keystroke):
SlashCommandTracker(plain class, NOT@Observable) readsdocumentContextBeforeInputafter each character/backspace/space/return- Walks backwards from cursor to find
/, validates it's at string start or after whitespace - Compares against last known state — only promotes to Phase 2 if
isActiveorqueryactually changed - Zero SwiftUI re-renders on the hot path
Phase 2 — Matching (SwiftUI side, reactive):
SlashCommandState(@Observable) holdsisActive,query, andmatchedSnippetsKeyboardToolbarViewuses.onChange(of: slashState.query)to trigger fuzzy matching- Snippets fetched via
@Queryin the toolbar view (not re-fetched per keystroke) - Fuzzy matching scores: prefix (100) > word-prefix (80) > substring (60) > ordered chars (40)
- Only text/URL snippet types are eligible (image/PDF excluded)
- Secure snippets shown but require biometric auth on tap
Key files:
SlashCommandEngine.swift—SlashCommandTracker+SlashCommandState+ fuzzy matching + environment keyKeyboardActions.swift—evaluateSlashCommandclosureKeyboardViewController.swift— creates tracker/state, wires evaluation closureQWERTYKeyboardView.swift—KeyboardToolbarViewwith suggestions UI +SlashTriggerButtonKeyButtonView.swift— callsevaluateSlashCommand()after character/backspace/return/space
After typing a character, the invisible touch boundaries between adjacent keys dynamically shift based on English bigram frequencies. For example, after typing "t", the hit area for "h" expands because "th" is extremely common. Visual keys don't change — only touch resolution logic changes. This is an inline per-key approach (no overlay or separate touch layer).
Architecture (inline per-key resolution):
KeyRowViewpre-computesProbabilisticRowDataonce per layout pass for letters-page rows 0-2. This containskeyRects(centerX, width per character key in row coordinate space),characters(row's character strings), andkeyOffsets(each key's tappable left edge X offset).- Each character
KeyButtonViewreceives this data as optional properties (rowKeyRects,rowCharacters,characterIndex,keyOffsetInRow). On numbers/symbols pages these are nil (zero overhead). - On touch-down,
KeyTouchAreapasses both the touch X and the control's actual UIKit frame. The character key's closure callsresolveCharacter()which converts local touch X to row-space X (localTouchX + keyOffsetInRow), fetches bigram weights fromProbabilisticTouchContext, and runsDynamicHitResolver.resolve(). - If the resolved key differs from the tapped key, the neighbor's character is inserted instead. The popup always appears above the tapped key's actual position (better UX — matches where the finger is).
Key files:
BigramEngine.swift— Staticenumwith pre-computed 26x26 English bigram conditional probability table.weights(after:)returns[Character: Float]. Also haswordInitialFrequenciesfor after space/punctuation. Allstatic letdata, zero allocations.DynamicHitResolver.swift— Staticenumwithresolve(touchX:keyRects:weights:keyGap:). Computes shifted boundaries between adjacent keys proportional to weight ratios. Clamps so no key shrinks below 60% of original width. Pure arithmetic, ~100ns.ProbabilisticTouchContext.swift— Plainfinal class(NOT@Observable— zero SwiftUI re-renders). TrackslastCharacterand pre-computescurrentWeights. Updated per keystroke viarecordCharacter()/recordNonCharacter(). Read byKeyButtonView.resolveCharacter().KeyRowView.swift—probabilisticRowData()method computes row geometry during SwiftUI layout.KeyButtonView.swift—resolveCharacter(),handleCharacterTap()methods.QWERTYKeyboardState.swift—QWERTYInputTracking.touchContextstores theProbabilisticTouchContextinstance.
Performance:
- ~100ns additional latency per keystroke (DynamicHitResolver arithmetic)
- Zero additional SwiftUI re-renders
- One small [Float] array allocation per keystroke (~40 bytes for 10 weights)
- No additional UIView instances at runtime
- Row geometry computed once per layout pass, not per keystroke
These channels are used by the snippet browsing view (KeyboardView.swift). The QWERTY keyboard uses direct closures via KeyboardActions instead.
| Notification | Purpose |
|---|---|
addKey |
Insert text or paste file into current input |
switchKey |
Switch to next keyboard |
deleteKey |
Delete character(s) |
spaceKey |
Insert space |
selectText / selectTextEmpty |
Text selection events |
hasFullAccess |
Full Access status broadcast |
- Keyboard extensions run in a constrained memory environment (~48 MB limit)
- Keep the UI lightweight — avoid adding
@Stateor@Observableproperties for per-keystroke visual effects - Full Access is required for
UIPasteboardoperations but not for text insertion - The extension shares the same SwiftData container via the
group.snipkeyApp Group - The keyboard extension cannot render views above its frame boundary (no private window access like Apple's native keyboard)
- For visual feedback, always prefer UIKit/CALayer approaches over SwiftUI state changes
This is a strict policy. All contributors must follow these rules:
- No analytics or tracking SDKs. Do not add Firebase Analytics, Mixpanel, Amplitude, or any similar SDK.
- No crash reporting SDKs. Do not add Crashlytics, Sentry, Bugsnag, or similar.
- No advertising SDKs. The app has no ads and never will.
- No third-party data sharing. Snippet content, user data, and usage patterns must never be sent to any external service.
- No network calls besides CloudKit sync (Apple's infrastructure) and RevenueCat (tip jar processing only).
- Biometric data is handled entirely by Apple's LocalAuthentication framework on-device. Never store or transmit authentication results.
- If a new feature requires network access, it must be clearly justified and documented.
struct MyNewView: View {
@Environment(\.modelContext) var modelContext
@Query(sort: \SnippetItem.creationDate) private var snippets: [SnippetItem]
var body: some View {
// View content
}
}
#Preview {
let container = SnipKeyDataManager().makeSharedContainer()
MyNewView()
.modelContainer(container)
}@Observable
class MyViewModel {
var modelContext: ModelContext? = nil
func performAction() {
// Business logic
try? modelContext?.save()
}
}If adding a new snippet type:
- Add a case to
SnipTypeenum inSnippetModel.swift - Handle the new type in
SnippetContentForm.swift(editor) - Handle the new type in
SnippetContentViewDisplay.swift(display) - Handle the new type in
KeyboardView.swift(keyboard paste behavior) - Update
SnippetViewModelif new CRUD logic is needed
When modifying KeyboardView.swift or KeyboardViewController.swift:
- Build and run the SnipKey scheme (not SnipKeyboard directly)
- Enable the keyboard in Settings if you haven't already
- Open any app with a text field (e.g., Notes)
- Switch to the SnipKey keyboard to test
- Use Xcode's Debug > Attach to Process to debug the extension
| Issue | Location | Notes |
|---|---|---|
| Dead code: unused ContentView | ContentView.swift |
Default Xcode template, references nonexistent Item model |
| Dead code: legacy home view | HomeView.swift |
Replaced by HomeView2.swift |
| Dead code: KeyboardHaptics enum | KeyButtonView.swift |
Haptic feedback disabled for iOS 26; enum kept for future settings toggle |
| No tests | — | Test targets exist in scheme but have no test files |
| Minimal error handling | Throughout | Most errors use print() and try? |
| Missing privacy manifest | — | .xcprivacy file not present; may be needed for App Store (UIPasteboard, UserDefaults declarations) |
| RevenueCat API key in source | RevenueCatManager.swift |
Public API key per RevenueCat design, but worth noting |
The project has a multi-phase roadmap to evolve SnipKey from a snippet-only keyboard into a full replacement keyboard (similar to Grammarly's iOS keyboard approach). The planned phases are:
Full QWERTY Keyboard(COMPLETE) — full QWERTY keyboard with letters/numbers/symbols pages, auto-capitalization, auto-period, caps lock, snippet toggle (tap) / globe (long-press), and key press visual feedback (balloon popup + highlight). Performance-optimized with UIKit touch handling,@Observableequality guards, and CALayer-based visual feedback.Slash Commands(COMPLETE) — type/snippetNameto trigger inline autocomplete in the toolbar. Two-phase evaluation (plain tracker + @Observable state) for zero per-keystroke re-renders. Fuzzy matching (prefix/word-prefix/substring/ordered chars). Biometric support for secure snippets. Usage tracking on selection. Slash trigger button in toolbar for quick activation.Probabilistic Touch Targeting(COMPLETE) — bigram-frequency-based dynamic hit boundaries for character keys. After typing a character, adjacent keys' invisible touch targets shift based on English bigram probabilities. Inline per-key resolution (~100ns per keystroke), zero SwiftUI re-renders, no additional UIView instances. Popup positioning uses actual UIKit frame viaconvert(bounds, to: nil).- Emoji Shortcodes — type
:emojiNameto autocomplete and inject emojis (Slack/Discord/GitHub-style shortcodes)
See the Roadmap & Vision section in README.md for full details, examples, and contribution guidance.
| App Store | https://apps.apple.com/us/app/snipkey/id6480381137 |
| GitHub | https://github.com/jtvargas/SnipKey |
| Website | https://snipkey.jrtv.online |
| Privacy Policy | https://snipkey.jrtv.online/privacy-policy |
| Feature Requests | https://snipkey.canny.io |