Wzorowane na reelu _code_and_chill_ ("the bar melts around it"), ale
technika wzieta z jego drugiego zdania: "every socket is solved for
tangency, so the liquid never creases". Czyli sciezka LICZONA, nie
rozmywana.
Filtr "goo" (rozmycie + prog alfy) byl pierwszym pomyslem i zostal
ODRZUCONY po zajrzeniu w zrodlo react-native-svg. Filtry na Androidzie
dzialaja (GroupView extends RenderableView, ktory obsluguje mFilter), ale
RenderableView.java:376 przy KAZDYM rysowaniu robi Bitmap.createBitmap(
canvas.getWidth(), canvas.getHeight(), ARGB_8888), rysuje do niej element,
naklada programowy filtr i wrzuca wynik z powrotem. Przy animowanej kropli
to pelnoekranowa alokacja na klatke, w nagłowku KAZDEGO ekranu.
liquidTabPath: gniazdo to dwa luki styczne jednoczesnie do krawedzi paska
(srodek na y=top+k) i do kropli (odleglosc srodkow = r+k), stad
dx = sqrt((r+k)^2 - (top+k-cy)^2). Jedna <Path>, zero alokacji.
Weryfikacja liczbowa (nie wizualna): trzy niezmienniki stycznosci trzymaja
sie do 1e-9, piec przypadkow brzegowych OK. Test wylapal brakujacy warunek
`cy - r < top`: bez niego wzor ma rozwiazanie takze gdy kropla siedzi CALA
w pasku (top=26, cy=45, r=17, k=12 -> dx≈28,1) i powstawaloby gniazdo, w
ktore nie ma sie co wtopic.
Animacja: Animated.Value + listener przepisujacy cx do stanu, bo sciezka
to string i nie da sie jej podac Animated wprost (brak Reanimated w
projekcie). ~12 re-renderow SVG na 200 ms przejscia, poza tym komponent stoi.
useNativeDriver=false swiadomie: animujemy geometrie, nie transform.
Etykieta aktywnej zakladki siedzi na wypelnieniu akcentu — jasny tekst daje
tam 5,03:1, jedyny wariant tego koloru przechodzacy AA (patrz theme.ts).