mrkeyoor.com_
Fri 02 Oct 14:59 UTC
Dev Toolsevaluationupdated 02 Oct 2026

Duo-animation review

Duo-animation is an Android demo that recreates the iPhone Duo folding illusion with Jetpack Compose, device sensors, and an AGSL runtime shader. It keeps an interface visually fixed while a tilted phone behaves like a frosted glass pane moving above it.

Verdict

Our install finished in 9 seconds, but build and tests both exited 126 because ./gradlew was denied execution. The Compose and AGSL source is worth reading if you need this exact illusion on API 33 or newer. Do not ship copied code until the author adds a license, and do not treat v1.0 as verified while the default checkout lacks a green build path and meaningful tests.

We ran it

Lab card: what happened when we ran Duo-animationScreenshot of Duo-animation (github.com/Atomicx7/Duo-animation)
Install✓ · 9s
Build✗ · 5s
Tests✗ · 11sran, no count parsed
Repo22 files~993 lines of source · 0.1 MB · 0 CI workflows

Answers from our run

Does Duo-animation build from source?

Dependencies installed in 9 seconds, and the build failed. We cloned commit 8e5be09 into a clean Debian container with 3 CPUs and no project-specific setup.

Do Duo-animation's tests pass?

The test command failed in our container, and its output did not report a pass or fail count.

Who should not use Duo-animation?

Anyone who needs clearly licensed reusable code: GitHub reports no license, and the repository contains no license file.

What are the alternatives to Duo-animation?

DuoLikeAnimation, Jetpack Compose samples, Android platform samples. Our install finished in 9 seconds, but build and tests both exited 126 because `.

Setup1/5Install passed; build and tests stopped at wrapper permission
Docs3/5Useful setup and tuning notes, with a shader tap mismatch
Community2/5224 stars and six open items, with no activity after September 12
Maturity1/5No license, CI, test directory, or verified lab build

Who it’s for

Android developers studying RuntimeShader and Compose graphicsLayer effects.
Teams prototyping motion-driven UI on physical API 33 or newer devices.
Shader developers who want a compact AGSL ray-plane projection example.
Readers comparing an Android port with the original SwiftUI implementation.

Who it’s NOT for

Anyone who needs clearly licensed reusable code: GitHub reports no license, and the repository contains no license file.
Apps supporting Android versions below API 33: the app's minSdk is 33 because the effect uses RuntimeShader.
Release gates that require a clean clone to build and test unchanged: both commands in our sandbox stopped at ./gradlew: Permission denied.
Teams expecting automated regression coverage: the repository has no tests directory and no CI workflow on its default branch.
Developers treating the README as exact shader documentation: it says 12 taps, while the checked-in AGSL loop runs up to 32 weighted iterations.

Setup reality

Our sandbox completed the install step in 9 seconds. The build failed with exit 126 after 5 seconds, and the test step failed with exit 126 after 11 seconds. Both log tails contain only bash: line 1: ./gradlew: Permission denied, so Gradle never supplied a build or test result.

The README calls for Android Studio Hedgehog or newer, Gradle 8.7, Android Gradle Plugin 8.5.2, SDK 34, and a physical API 33 or newer device. No account or API credential is required.

The emulator lacks the rotation-vector sensor used by the effect and falls back to a manual slider. The 22-file repository has no Dockerfile, tests directory, or CI workflow, so you must establish the build and device-test path yourself.

API 33 is the floor because AGSL powers the illusion

The app sets minSdk to 33, compileSdk and targetSdk to 34, and Java compatibility to 17. Its central modifier loads an AGSL file from resources, creates an Android RuntimeShader, passes the current size and tilt as uniforms, then applies the result through a Compose graphicsLayer. This is an application project under the example package name, not a library module prepared for consumption from another build.

The geometry follows the same model as the Swift project it credits. A flat interface remains on its original plane while an imaginary glass layer rotates around the farther edge. Each shader invocation projects a pixel through that glass back to the interface, adds blur based on the gap, and darkens the result. Pixels whose projection misses the content become black. The hinge switches sides with the sign of the tilt.

The sensor model adds a 15-second recentering baseline

FoldMotionModel prefers Android's game rotation vector, falls back to the fused rotation vector, and uses a gyroscope when available. It maps sensor coordinates to the current display rotation, predicts 0.04 seconds ahead, smooths the angle, and limits output to 45 degrees in either direction. A 15-second baseline slowly absorbs drift only while angular motion stays below its stillness threshold.

Those choices are more involved than the short README suggests. The model exposes tilt, hinge side, and sensor availability as StateFlow values. Recalibration resets the reference pose, while manual mode provides an emulator path. Physical feel still needs hardware judgment across devices because display density, sensor availability, orientation mapping, and sensor latency differ. Our lab did not measure animation quality or frame behavior.

The README's 12-tap note disagrees with the 32-step shader

The tuning section says the current effect uses 12 taps. The checked-in duo_fold.agsl instead calculates a dynamic count between 6 and 32, then executes a fixed 32-iteration loop with weights masking unused samples. That implementation may be intentional for AGSL compatibility, but the two descriptions do not match. Anyone optimizing the shader should trust the source and profile the target phone.

Defaults differ from the iOS reference in another visible way. FoldParameters uses a 450 mm eye distance, despite the README's model summary naming 320 mm. Pixel density is resolved from xdpi when the caller leaves it at zero, with a 6-pixel-per-millimeter fallback. These are tunable inputs, not universal physical constants. Save known-good values per layout instead of assuming one preset will suit every screen.

What happened when we ran it

Our JVM sandbox completed its install step in 9 seconds. The 0.1 MB checkout contained 22 files and about 993 lines of source. Build then stopped after 5 seconds with exit 126. The only reported line was bash: line 1: ./gradlew: Permission denied. There was no compiler output or Gradle task result to interpret.

The test step reached the same boundary after 11 seconds and exited 126 with the same line. The repository has no tests directory, no CI workflow, and no Dockerfile. Its gradlew file is present, as is the Gradle 8.7 wrapper jar, but our result establishes only that the supplied command could not execute the wrapper in the fresh container. It does not establish whether the Android source compiles after that boundary is removed.

No license and no green CI block direct reuse

GitHub reports no detected license, and the 22-file tree contains no license document. Public visibility does not grant permission to copy the code into a product. Until the author chooses a license, this repository is safest to use as something to read and discuss, not a source file donor. The iOS reference has an MIT license, but that license does not automatically cover this separate Android port.

The default branch also has no automated build. Pull request 1 proposes a GitHub Actions workflow for a debug APK, but it remains unmerged. There are no source tests behind ./gradlew test, and our command never reached Gradle anyway. A serious fork needs a reproducible wrapper invocation, a compile check, shader initialization tests where feasible, and device acceptance checks for both hinge directions.

v1.0 shipped on September 10, followed by two days of activity

Release v1.0 was published on September 10, 2026, the same day the repository was created. GitHub showed 224 stars and 6 combined issues and pull requests on October 2. The last push was September 12, and the open items had no later activity. That is a short project history, though it is too early to label the project abandoned.

Duo-animation succeeds as a concise explanation of how this effect maps to Compose, sensors, and AGSL. It falls short as a dependency: no license, no verified default build, no test suite, and stale details in the tuning notes. If the visual is important, recreate the method in a licensed module with a small API and test it on the Android devices you support.

Alternatives

ProjectWhat it isPick it when
DuoLikeAnimation gh↗The SwiftUI and Metal implementation that this Android project ports.pick this instead when the target is iOS and the app can require iOS 26.5.
Jetpack Compose samplesGoogle's maintained sample applications for Compose architecture and UI APIs.pick this instead when you need official, licensed examples across Compose rather than one shader effect.
Android platform samplesGoogle's collection of examples for Android platform APIs.pick this instead when platform coverage and maintained sample conventions matter more than the Duo illusion.

What people are saying

  1. [velocity-scout] Atomicx7/Duo-animation

Sources

  1. Duo-animation README
  2. Duo-animation v1.0 release
  3. Android app build configuration
  4. AGSL fold shader
  5. Motion model
  6. CI workflow pull request 1

More dev tools reviews

touchHLE · effect · SwitchHosts · DuoLikeAnimation · team-Omzo · lid-plane · the whole board →