跪拜 Guibai
← All articles
Frontend · Android · Kotlin

Five Physics and Shader Effects That Push Jetpack Compose Past Simple Lists

By 杉氧 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Compose is often dismissed as a layout engine for forms and lists. These five demos show the same framework can drive cinema-grade physics, shaders, and particle systems at 120 fps on mid-range Android hardware — and the same Kotlin code ships on iOS via Compose Multiplatform.

Summary

ComposeCraftLab is an open-source lab of five high-end Compose Multiplatform effects — gooey fluid fusion, 3D parallax cards, jelly physics, GPU shader plasma, and a 500-particle gravity system — built to test the rendering ceiling of declarative UI. The gooey effect replaces the standard Gaussian-blur approach (API 31+, frame drops on mid-range devices) with a pure-math solution using common tangents and quadratic Bézier curves that runs cross-platform with zero latency. The 3D card demo fixes Compose's flat default rotation by manually setting `cameraDistance` for real perspective projection, then drives a reverse-direction specular highlight with `LinearGradient` offsets. A jelly ball models area-conserving stretch — elongating along the drag axis while compressing perpendicularly — and snaps back with a low-damping spring (`stiffness 150f`, `dampingRatio 0.35f`).

The GPU shader lab targets Android 13+ AGSL, piping touch coordinates as uniforms into a fragment shader that computes dot-product and cosine-wave fields for real-time liquid-metal and quicksand textures. The particle galaxy runs 500 independent particles on a Canvas, applying centripetal acceleration toward screen center for spiral-disk motion and a 300px repulsion field around the finger. Frame scheduling uses `withFrameMillis` to lock to the display refresh rate, hitting stable 60/120 fps. Two performance rules emerge: never allocate `Path`, `Brush`, or `Paint` inside `DrawScope` — cache them in `remember` to avoid per-frame GC — and push pure transforms onto `Modifier.graphicsLayer` so the GPU handles matrix changes without recomposing the UI tree.

Takeaways
Gooey fluid fusion replaces Gaussian blur + alpha threshold (API 31+) with a pure-math common-tangent and quadratic Bézier curve approach that works on any API level without frame drops.
3D parallax cards require manually setting `cameraDistance` (e.g., `14f * density`) in `graphicsLayer` to get real perspective projection instead of Compose's default flat rotation.
A jelly stretch effect conserves area by scaling up along the drag vector (`stretchFactor = 1 + dragDistance/250`) while scaling down perpendicularly (`squeezeFactor = 1/stretchFactor`).
AGSL fragment shaders on Android 13+ accept touch coordinates as uniforms, enabling real-time GPU-computed plasma, liquid metal, and quicksand textures inside Compose's `RuntimeShader`.
A 500-particle gravity galaxy runs at full display refresh rate (60/120 fps) by scheduling redraws with `withFrameMillis` and applying centripetal acceleration plus a 300px finger-repulsion field.
Never allocate `Path`, `Brush`, or `Paint` inside `DrawScope` — cache them in `remember` to prevent per-frame GC that causes UI stutter.
Push rotation, scale, and translation changes onto `Modifier.graphicsLayer` so the GPU handles the matrix transform directly, avoiding a full UI-tree recomposition.
Conclusions

The gooey effect's pure-math approach is a direct rebuttal to the assumption that advanced fluid visuals require high API levels or GPU filters; it's just trigonometry and Bézier curves, making it viable on low-end devices and older Android versions.

Manually tuning `cameraDistance` is a hidden lever many Compose developers never touch, yet it's the difference between a card that looks like a flat parallelogram and one that reads as a genuine 3D surface with depth.

The area-conserving jelly model — stretch one axis, compress the other — is a simple but physically grounded trick that sells material realism far more convincingly than uniform scaling ever could.

Running 500 particles with per-frame vector math and touch interaction at a stable 120 fps on a Canvas is a strong counterpoint to the narrative that Compose can't handle high-frequency redraws for game-like or data-viz UIs.

The two performance rules — cache draw objects and isolate transforms on `graphicsLayer` — are not Compose-specific novelties; they echo the same allocation-avoidance and render-thread-offloading patterns that game and graphics engineers have followed for decades.

Concepts & terms
AGSL (Android Graphics Shading Language)
A C-like shading language introduced in Android 13 for writing GPU fragment shaders. In Compose, AGSL shaders run via `RuntimeShader` and can accept uniform inputs such as touch coordinates, enabling real-time procedural textures without CPU-side pixel manipulation.
cameraDistance
A `graphicsLayer` property in Compose that controls the virtual camera's distance from the drawing plane. The default value produces weak perspective; increasing it (e.g., `14f * density`) strengthens the 3D projection effect so that rotations around X and Y axes read as genuine depth rather than flat skewing.
withFrameMillis
A Compose animation function that provides the frame time in milliseconds and synchronizes redraws to the display's vsync signal. Using it for Canvas drawing ensures animations run at the device's native refresh rate (60 Hz, 90 Hz, or 120 Hz) without redundant frames.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗