IRO UTSUSHI
An app that never asks you to name a feeling. Drop color onto water, stir it with your finger, and the movement of your hand stays behind as a single picture.
Available on the App StoreWhat you can do
- Drop color and stir it … Drop up to five colors from a palette of six onto the water and stir them into one picture with your finger. The two palettes, “calm colors” and “vivid colors”, can be switched even after you have dropped color.
- No words, no categories … There is no list of moods to pick from and no label to add afterwards. What remains is only the trace of color and finger movement.
- Up to 60 seconds per recording … The approaching end is announced with ripples, a glow, and sound. It never uses vibration to hurry you.
- Four measures of movement … Speed (the median of instantaneous velocity), spread (mean distance from the center of gravity), variation (how often you change direction, plus the scatter in speed), and dynamics. They are hidden by default on the result screen: an app that refuses to categorize should not lead with a score.
- Play it back … The water is rebuilt from the stored touch sequence and replayed, at 1× or 2×, with seeking forwards and backwards. The path of your finger and the points you tapped can be drawn over the water.
- Export and share … Export as 30 fps MP4 with sound, or as PNG. Flip through your history with an up-and-down swipe, and delete several recordings at once.
- Sound made inside the app … Where you tap becomes a note in a pentatonic scale; how fast you move becomes volume and the brightness of the overtones. Five voices are available: soft keys, kalimba, harp, string pad, and glass harmonica.
- Accessibility and ten languages … Built with low-vision users in mind, with support for Dynamic Type, VoiceOver, Increase Contrast, Reduce Transparency, and Reduce Motion. Available in Japanese, English, Spanish, French, Korean, Traditional Chinese, Brazilian Portuguese, German, Italian, and Vietnamese.
How it is built
| App | Swift + SwiftUI, written as a Swift Playgrounds App Package, with zero external package dependencies. |
|---|---|
| Water | A fluid simulation written in Metal. The velocity field, pressure projection, advection, vorticity confinement, and pigment mixing all run on the GPU. |
| Pigment | Held as Lagrangian particles and layered with subtractive mixing following the Beer–Lambert law. Because they are particles, they do not blur away through diffusion over time. |
| Look | Refraction and speculars drawn from normals derived analytically from the height field of the water, plus a grain noise and dithering to avoid banding. |
| Input | Taken from raw UIKit events, passing every coalesced touch within a frame to the fluid. Up to five simultaneous touches are recorded, replayed, and measured as independent strokes, one per finger. |
| Storage | The history list holds only lightweight information in JSON; the image is a single PNG; the touch sequence is fixed-width binary compressed with LZFSE, in a directory of its own per recording. |
| Replay and export | The water is rebuilt by rerunning the simulation from the stored steps. MP4 is not a screen recording: frames are recomposed from those steps and written out at 30 fps. |
| Sound | Synthesized inside the app, a pentatonic scale with up to 16 voices. There are no audio files. |
| Self-checks | Since the environment cannot host XCTest, a set of checks written for this app (SelfChecks.swift) runs on debug launch instead. |
| Encryption | None at all; the export compliance answer ships with the app. |
The interesting parts
The tail keeps curling after your finger has passed
Advection carries a MacCormack correction, which preserves the thin vortices that plain semi-Lagrangian advection erases. A finger does not push the water: it drops a counter-rotating vortex pair along the direction of the drag, so the water keeps curling for a while after the finger has gone. Every damping and follow coefficient is expressed per second, so the motion is the same on a 60 Hz device and a 120 Hz one.
Separating the wave you see from the wave that moves things
The visible strength of a ripple and its effect on pigment are separate parameters. And a ripple moves the position of the pigment directly, not its velocity. Pigment velocity is pulled back towards the velocity of the water every frame — with a time constant of roughly 0.36 seconds in dense areas — and a ripple lives for less time than that, so measurement showed that adding velocity barely moved the pigment at all. Tuning the look and tuning the feel no longer break each other.
Deciding not to make pigment attract pigment
There used to be a cohesion force pulling pigment together, but the only place it could settle was a round blob: given enough time the water filled up with opaque circles that never came apart again. The edge darkening of watercolor is now reproduced without moving any pigment. The density field stays as it is, and the edge is drawn from it as shading on the water surface path, so nothing about the picture sets solid.
The same recording always replays as the same picture
The simulation is fixed at 60 steps per second, and each recording stores the actual step numbers at which UIKit input was consumed, the number of lead-in steps, and a sidecar of Float32 timestamps with UInt16 coordinates.
Replay trusts those stored steps over the wall-clock timestamp. Speed is measured against UITouch.timestamp, because movements within a single frame cannot be told apart by the wall clock.
Predicted touches are used only for estimating speed; they never affect where pigment lands.
On top of that, SimulationEngineRegistry routes each stored simulationVersion explicitly to the engine that matches it.
Version 6 is frozen down to its constants, its clock, and its ink transfer rate, and an unknown future version is never quietly fed to the newest simulation.
The point is that the picture of an old recording is not rebuilt into something else by an app update.
Not showing the score first
The four measures are not clipped at a ceiling; they sit on a curve that approaches 100 asymptotically, so one quick movement does not earn full marks. Even then, they are hidden by default on the result screen. If an app that refuses to sort feelings into words leads with numbers, those numbers simply become the new label.
Privacy and contact
IRO UTSUSHI stores your recordings on your device only. It has no account registration, no advertising, no analytics, and no features that track users. For details, see the IRO UTSUSHI Privacy Policy.
For feedback and bug reports, you can also reach us through the Sizu dev contact page.