Proiecte/Liquid Glass
Liquid Glass
O bibliotecă de componente React Native. Sticla nativă Apple pe iOS 26 și o alternativă în JS și SVG, fidelă până la pixel, peste tot altundeva. O singură componentă, nivelul potrivit pentru fiecare dispozitiv.
- ROL
- Design și dezvoltare
- AN
- 2025–2026
- PLATFORMĂ
- Bibliotecă privată
- STARE
- În producție

ParticleRings, o mie cinci sute de orbi, în mișcare
05 / 05
Screen 5 of 5: ParticleRings, o mie cinci sute de orbi, în mișcare
O componentă n-ar trebui să-l pună pe cel care scrie aplicația să se gândească la ce versiune de iOS are utilizatorul.
Pe un iPhone cu iOS 26, un buton de sticlă e chiar materialul Apple și îți urmărește degetul așa cum o face sistemul de operare. Pe un telefon din 2018 e o reconstrucție în JavaScript și SVG pe care aproape nimeni n-o observă ca reconstrucție. Linia pe care o scrie autorul aplicației e aceeași, iar faptul că rămâne aceeași e tot produsul.
Șase din cele optsprezece pachete sunt în Swift și niciunul dintre ele nu e sticla. Sunt părțile care nu pot fi imitate deloc: camera de scanare, decuparea subiectului, recunoașterea de text, Apple Health, widgeturile de pe ecranul principal. Sticla are o alternativă pentru că o alternativă e posibilă. O cameră nu are.
Nu e o demonstrație. Rulează în producție în TeamTipOut și în alte două aplicații, care e singurul motiv pentru care știu ce e de fapt în neregulă cu ea. Fiecare dintre aplicațiile alea a găsit ceva ce o aplicație de previzualizare n-ar fi găsit niciodată.
Toată biblioteca e un singur pariu: că decizia de nivel aparține componentei, nu aplicației. Tot restul decurge de aici.
În producție în TeamTipOut și în alte două aplicații, dar nepublicată. E biblioteca din care pornesc proiectele clienților, așa că un proiect care o folosește începe de la componente care au trecut deja printr-o verificare de magazin, nu de la un fișier gol. Design și dezvoltare în întregime ale mele.
- STARE
- În producție
- DISTRIBUȚIE
- Privată: folosită pe build-urile mele
- FOLOSITĂ DIN
- 2025
59 de componente.Optsprezece pachete, șase dintre ele native.
Nu am ecrane să-ți arăt, pentru că o bibliotecă nu are. Ce are sunt piese. Astea, în aplicația-galerie în care sunt toate construite.
- PACHETE
- 18
- COMPONENTE
- 59
- MODULE NATIVE
- 6
- APLICAȚII ÎN PRODUCȚIE
- 3
Fundamente
Text · Button · Input · OtpInput · InlineErrorNotice · SectionHeader
Indicatori
AnimatedCheckIndicator · AnimatedRadioIndicator · CheckmarkGlyph · ProgressBar · MetricBar · MetricProgressBar · ScoreRing · SmallProgressRing · SkeletonBlock · AnimatedNumber
Layout și suprafețe
SurfaceCard · NavRow · SeeAllSection · ScreenHeader · EdgeFade · Entrance
Panouri și gesturi
BottomSheet · CollapsingTitle · FloatingSheet · SheetSubmitCta · CloseButton · SwipeableActionRow
Sticlă lichidă
LiquidGlassSurface · LiquidGlassView · LiquidGlassButton · LiquidGlassIconButton · LiquidGlassSwitch · LiquidGlassSlider · LiquidGlassSegmentedControl · LiquidGlassTabBar · LiquidGlassMenu
Mișcare cu Skia
ParticleRings · AmbientDust · CelebrationRing · DotWaveField · ShaderLoadingTrack
Subcăi cu dependențe opționale
LargeScoreRing · RemoteImage
Grafice
BarChart · RadarChart
Serii de obiceiuri
StreakCalendar · StatusRingDayCell · MilestoneBadge · MilestoneTrackSegment · ActivityLegend
Monetizare
PremiumBlur · PremiumSectionLock · PremiumScreenLock
Provideri și efecte la derulare
ThemeProvider · FontProvider · ScrollAwareTopBlur · SkiaReframeImage
Wizard
WizardLayout
Două decizii care merită explicate.Părțile care au durat cel mai mult.
D—01
Nimeni nu întreabă ce iOS e ăsta
Abordarea evidentă e două componente și o verificare de versiune în aplicație. Asta mută problema pe umerii fiecărui autor care folosește biblioteca și garantează că cele două căi se despart în momentul în care una dintre ele primește o corectură.
Așa că biblioteca nu întreabă niciodată pe ce iOS rulează. Întreabă dacă s-a încărcat modulul de sticlă al Apple și apoi dacă modulul acela spune că propriul lui API e disponibil. Un pachet poate fi instalat pe un telefon prea vechi ca să-l ruleze, iar numărul de versiune ți-ar fi spus oricum altceva decât trebuie. Două întrebări, niciun număr de versiune, iar la a doua răspunde Apple, nu eu.
Cache-ul are trei stări, nu două. Undefined înseamnă că n-a întrebat nimeni încă; null înseamnă că întrebarea a fost pusă și răspunsul a fost nu. Fără distincția asta, un dispozitiv fără modul reia un require care eșuează la fiecare randare a fiecărei suprafețe de sticlă de pe ecran.
let resolved: GlassEffectModule | null | undefined; if (resolved !== undefined) return resolved;resolved = null;if (Platform.OS !== 'ios') return resolved; try { const mod = require('expo-glass-effect'); // installed is not the same as supported if (mod.isGlassEffectAPIAvailable?.() && mod.GlassView) resolved = mod;} catch { resolved = null; }D—02
Ce m-a învățat producția
Un crash pe New Architecture la o valoare fracționară de slider. Un control segmentat care se strica dacă era măsurat înainte ca etichetele lui să termine de așezat. Niciunul nu apare într-o aplicație de previzualizare, pentru că o aplicație de previzualizare nu ține niciodată o valoare venită de la un utilizator real și nu randează sub presiune reală de layout.
Amândouă au fost găsite folosind biblioteca în TeamTipOut. Ăsta e argumentul pentru a-ți trimite propriile unelte în propriul produs. Bug-urile care contează sunt cele care ies la iveală doar când ceva chiar depinde de ele.
## 0.9.2, found in TeamTipOutfix: clamp slider value before the bridge 0.5 crossed as double, Swift wanted a step ## 0.9.1, found in TeamTipOutfix: defer segmented measure until layout width read before the font had loadedD—03
O mie cinci sute de orbi, un singur apel de desenare
Înregistrarea din capul paginii e cea mai grea vedere din bibliotecă și e acolo pentru că o imagine statică nu poate arăta singurul lucru care merită arătat: că rata de cadre se ține.
O mie cinci sute de orbi difuzi e un număr ales ca să fie incomod. Desenat pe calea evidentă înseamnă o mie cinci sute de apeluri de desenare pe cadru și un telefon care se încălzește. Desenat ca un singur atlas grupat, e un singur apel către GPU, iar munca pe cadru devine proporțională cu numărul de orbi, nu cu numărul de pixeli pe care îi acoperă, motiv pentru care roiul poate fi dens fără să fie scump.
Pozițiile se calculează într-un worklet pe firul de UI, așa că un fir de JavaScript ocupat nu poate să sacadeze animația. Fiecare constantă de reglaj stă în JavaScript simplu, în capul fișierului, pentru că un roi se reglează uitându-te la el, iar recompilarea ca să schimbi o rază e felul în care te oprești din a te mai uita.
const DEFAULT_COUNT = 1500; // the tuned densityconst ORB_RADIUS_FACTOR = 0.022; // one batched GPU call, not one per orbSkia.drawAtlas(sprite, transforms, colors); // O(orbs), not O(pixels x orbs)useDerivedValue(() => positionsFor(clock.value));PE CE E CONSTRUIT
- LIMBAJ
- TypeScript strict · Swift · punți Objective-C
- RUNTIME
- React Native New Architecture · Fabric · TurboModules
- PACHETE
- 18 pachete · 6 dependențe native opționale
- DISTRIBUȚIE
- Versionată cu Changesets · CI pe GitHub Actions
CREDITE
Design și dezvoltare în întregime ale mele.
STARE
O bibliotecă privată, care rulează în producție în TeamTipOut și în alte două aplicații. Nu există un repository public către care să trimit.
PROIECTUL URMĂTOR
CoffeeBrew
Un espressor într-o aplicație: împerechere prin Bluetooth, configurare Wi-Fi, preparare programată și un widget pe ecranul principal. Scrisă pe un protocol, nu pe un produs.
Spune-mi ce construiești.Un plan scris și un preț fix înainte să se miște vreun ban.
Răspund la tot într-o zi lucrătoare. Dacă nu sunt omul potrivit pentru proiect, ți-o spun din start, nu după trei săptămâni.




