IRO UTSUSHI

一款不會要你替心情命名的應用程式。把顏色滴進水面、用手指攪動,當下的手勢就這樣留成一張畫。

已在 App Store 上架
  • 應用程式
  • iPhone / iPad
  • Swift
  • SwiftUI
  • Metal
在 App Store 下載

可以做什麼

怎麼做的

應用程式 Swift + SwiftUI,以 Swift Playgrounds 的 App Package 撰寫,完全不依賴外部套件。
水面 以 Metal 撰寫的流體模擬。速度場、壓力投影、對流、渦度強化與顏料混合全部交由 GPU 處理。
顏料 以拉格朗日粒子保存,依 Beer–Lambert 定律做減法混色。因為是粒子,經過一段時間也不會因擴散而糊掉。
外觀 由水面高度場解析求得法線,據以繪製折射與高光,再疊上顆粒雜訊,以及用來避免色帶的抖色處理。
輸入 取自 UIKit 的原始事件,把同一影格內的 coalesced touches 全數交給流體。最多五指同時觸控,會以每根手指各自獨立的筆觸來記錄、播放與計算。
記錄的儲存 清單用的 JSON 只放輕量資訊,影像是一張 PNG,觸控序列則以固定寬度的二進位資料經 LZFSE 壓縮,各自存放在每筆記錄專屬的目錄中。
播放與輸出 依儲存的 step 重新跑一次模擬來重建水面。MP4 並非螢幕錄影,而是從那些 step 重新合成影格後以 30 fps 寫出。
聲音 音效在應用程式內合成,五聲音階、最多 16 個聲部同時發聲,不放任何音檔。
自我檢查 由於環境無法使用 XCTest,改以自行撰寫、在除錯啟動時執行的檢查(SelfChecks.swift)來代替。
加密 完全未使用(並隨附 export compliance 的回覆)。

技術上有意思的地方

手指走過之後,尾流仍在捲動

對流加上了 MacCormack 修正,單純的半拉格朗日對流會抹掉的細小渦漩,因此得以留存。 手指不是「推」水,而是沿著拖曳方向落下一對反向旋轉的渦,所以手指離開後,水仍會繼續捲上一陣子。 衰減與跟隨的係數一律以「每秒」表示,因此在 60 Hz 與 120 Hz 的裝置上動態一致。

把「看得見的波」和「會推東西的波」分開

波紋的可見強度與它對顏料的作用是兩個不同的參數。而且波紋直接改變顏料的位置,而不是速度。 顏料的速度每一影格都會被拉回水流的速度,在濃處的時間常數約為 0.36 秒,而波紋的壽命比這更短, 實測顯示:以加速度的寫法,波紋幾乎推不動顏料。如此一來,調整外觀與調整手感就不會互相破壞。

刻意不讓顏料互相吸引

過去曾加入讓顏料聚攏的「凝聚」力,但它唯一的安定狀態只有圓形團塊;時間一久,水面就被不透明的圓填滿,再也化不開。 現在改以不移動任何顏料的方式重現水彩的邊緣沉積:濃度場維持原樣,只是從中取出邊緣,當作水面路徑上的陰影來繪製,因此畫面不會就此凝固。

同一筆記錄,重播多少次都是同一張畫

模擬固定為每秒 60 個 step,並將消耗 UIKit 輸入的實際 step 編號、前導(lead-in)step 數,以及 Float32 時刻搭配 UInt16 座標的附屬檔一併保存。 播放時以這些儲存的 step 為準,而非系統時鐘的時間戳。速度則以 UITouch.timestamp 為基準(同一影格內的動作,用系統時鐘無法區分)。 預測觸控只用於估計速度,不會影響顏料落下的位置。

在此之上,SimulationEngineRegistry 會把記錄中的 simulationVersion 明確導向對應的引擎。 version 6 連常數、時鐘與墨水傳遞率都已凍結,且不會把未知的未來 version 悄悄交給最新的模擬處理。 為的是讓舊記錄的畫面,不會因為應用程式更新而被重建成另一張畫。

不把分數擺在最前面

四項指標不以上限截斷,而是放在漸近於 100 的曲線上,快速動一次並不會拿到滿分。 即便如此,結果畫面仍預設隱藏它們。一款不用文字為情緒分類的應用程式,若先端出數字, 那些數字終究會變成新的標籤。

隱私權與聯絡方式

IRO UTSUSHI 只把記錄保存在你的裝置中,沒有帳號註冊、沒有廣告、沒有流量分析,也沒有追蹤使用者的功能。 詳情請見 IRO UTSUSHI 隱私權政策。

意見與問題回報,也可以透過 Sizu dev 的聯絡頁面與我們聯繫。