User signal 2026-06-20. The user's first request to push Hydrolyze's
feel in a direction beyond the existing VISION.md framing of
"information-rich effortlessness." The verbatim ask: **"Lets work
on micro interaction for the hydrolyze app. haptic feedback,
animations etc. make the app feel playful etc. look at the existing
UI components and aduit them and improve them—go through with a fine
tooth comb, searching for areas on improvement."** (User wrote "aduit"
— preserved verbatim, not auto-corrected.)
Hydrolyze's existing VISION.md principle is information-rich effortlessness — a professional tool for swim coaches at 5am with 24 swimmers in the water. The previous design system was deliberately restrained:
LAP tap)
The new direction adds a layer the old framing explicitly didn't have: playfulness. This sounds contradictory with "professional tool for 5am pool deck." The resolution:
| Element | Old framing | New framing | Why |
|---|---|---|---|
| Haptics | Not used (zero) | Semantic vocabulary across the app | Tactile confirmation works THROUGH pool-deck noise (echoes, splashes). The medium LAP haptic is felt even when the coach isn't looking. |
| Animations | Only cyan flash on LAP | Spring physics on existing animations + invitation pulses on idle | Spring is more "decisive," not "bouncy." Invitation pulses (breathing) are subtle — 1.04 scale, 1.4s cycle, fades the cyan glow. |
| Press feedback | Invisible default iOS opacity tick | StrongPressFeedbackStyle on primary CTAs | The 200pt cyan START button was so big the opacity tick was invisible. Scale-down (0.92) on press is felt. |
| Empty states | Static house icon | Breathing scale (1.0 → 1.06 → 1.0, 1.6s) | "Alive but patient" — not "pulsing alert." |
The principle: playful ≠ gamey. Playful means the app feels like it CARES about the experience. Gamey means the app is a toy. Hydrolyze stays a professional tool; the playfulness is in the responsiveness, not the whimsy.
Before the 2026-06-20 work, the iOS native codebase had:
primary action, tapped dozens of times per session — had no tactile feedback.
lapFlashOpacity on LAP, easeOut(0.3s)).compressed invisibly on tap.
SessionReviewView or SwimmersListView— rows popped in.
swap was a hard cut.
the tap.
See Hydrolyze Micro Interaction System for the system architecture. Summary:
Haptics.swift — semantic enum with one vocabulary across the appPressFeedbackStyle.swift — ButtonStyle + view modifierAnimations.swift — shared curves: snap / gentle / springSnappy /springSoft / breathing
All three are in Hydrolyze/Sources/Lib/. One file per concern. Future iOS work should reach for these instead of constructing ad-hoc haptics, press effects, or animation curves.
74 interaction points across 11 files. Per-file breakdown:
| File | What changed |
|---|---|
TimingView | LAP = medium haptic + spring flash + press compression. START = breathing phaseAnimator invitation pulse. STOP = heavy haptic (tactile "are you sure"). Cyan flash: easeOut → spring. SAVE = success haptic. DISCARD = heavy. |
SessionReviewView | Filter tabs = selection haptic + animated background swap. Row tap = tap haptic. Inline ✓ accept = success. Mark intensity = success. ReassignSheet select = action. Confirm button = StrongPressFeedbackStyle + warning haptic on .withFlagged. Alert buttons = selection/success. Row enter/exit = asymmetric transitions. |
LoginView | Mode switch transitions via withAnimation(Animations.gentle). Success/error/warning haptics. Selection haptic on link taps. |
SwimmersListView | + toolbar = action. Filter pills = selection + animated morph. Swipe archive + long-press delete = heavy. |
PrimaryButton | Tap haptic + press feedback + breathing glow shadow. |
AuthTextField | Selection haptic on focus. Animated border + label color shift on focus change. |
WorkoutCard | AM/PM amber badge breathing. |
EmptyStateView | House icon breathing. |
Parse-verified all 11 files (zero errors). Did NOT run a real xcodebuild (needs Mac Studio). Did NOT add unit tests.
→ .running → .finished state machine still does hard swaps on the ZStack. With withAnimation wrapping the state changes plus .transition(.opacity.combined(with: .scale))` on the ZStack children, the transitions could be smooth. Not done in this pass — the per-button work was higher impact. Captured for v1.16+.
iOS but coming) would be the right escalation. Captured for v2.
a lap is recorded into the review surface would be a satisfying matched-geometry. Not done — would need surface redesign.
respect accessibilityReduceMotion and degrade to static. Not yet wired; future accessibility pass.
After the v1.16 micro-interaction audit landed, the user gave a sharp direction shift on how to express the "warm" voice the playful direction was already implying: "Let's go with 'warm.' We should try to make it feel welcoming and interactive. We can do this through the UI animations and how the user interacts with the app, rather than focusing on the text components."
The principle: voice in product design is multi-channel. For a pool-deck timing tool (read-by-glance, not read-by-word), the right channel is motion + interaction, not text. The clinical text conventions (HYDROLYZE, REVIEW, LAP, READY, SESSION COMPLETE) STAY — they read cleanly on a pool deck at 5am. The warmth comes from how the app responds, not what it says.
What "warm through motion" looks like in Hydrolyze:
Animations.springSnappy or springSoft, never plain easeInOut. The bounce/punch of a spring feels ALIVE.
gently when idle (the v1.16 START button work; extend pattern).
+ haptic + color shift, BEFORE the async work. The user knows the tap registered even before the result.
.ready → .running, filter tabs, login modes), the transition is a smooth crossfade with subtle scale. Not a hard cut.
physics. The list feels ALIVE.
user sees progress, not "stuck."
is the canonical example. No text. Tick mark animation + haptic.
pattern, generalized to all empty states).
See Warmth Through Motion for the full principle, cross-cutting posture generalization (Felt Faction's text-channel warmth vs. Hydrolyze's motion-channel warmth), and the critique of LLM default-to-text behavior on "feel" directives.
Per Felt Faction iOS app v2 — replacement direction + chip-counting, Felt Faction already cited "Haptic feedback" as a Hydrolyze pattern to lift. With Hydrolyze now having haptics properly implemented, the patterns in Haptics.swift and PressFeedbackStyle.swift can be ported to the Felt Faction iOS app verbatim — they're pure utility files with no Hydrolyze-specific dependencies.
Felty's voice (Felty) also pairs naturally with haptics: each Felty narration point (loan offer, interest debit, phoenix earned) should have a matching haptic at the iOS layer.
architecture (3 utilities, design vocabulary, cross-cutting rules)
rich effortlessness" principle being extended, not replaced
— Felt Faction citing Hydrolyze haptic patterns to lift
hydrolyze app. haptic feedback, animations etc. make the app feel playful etc. look at the existing UI components and aduit them and improve them—go through with a fine tooth comb, searching for areas on improvement."
the local memory tool. Captured as preference signal.
Hydrolyze/Sources/ at the 2026-06-20 audit baseline. Engine, prediction, and SessionReview v1.14 polish work (commit fef54a1 + slice 1 9db019e) was the prior baseline.
Published and managed by TARS, an AI co-author built on Nathan's gbrain.