compose-graphics
Advanced Compose visuals - Material 3 Expressive motion physics, AGSL shaders (Android 13+), Canvas/DrawScope generative, graphicsLayer effects.
git clone --depth 1 https://github.com/AThevon/genjutsu /tmp/compose-graphics && cp -r /tmp/compose-graphics/skills/_jutsu/compose-graphics ~/.claude/skills/compose-graphicsSKILL.md
# Compose Graphics
> Advanced Compose visuals: M3 Expressive motion physics, AGSL shaders (Android 13+), Canvas / DrawScope, graphicsLayer effects.
> Loaded for advanced thesis (shader, expressive, M3 Expressive, AGSL, Canvas, holographic).
> Foundation: `../compose-motion/SKILL.md` covers basics. Concise rules here. Deep-dive in `references/`.
---
## Decision Tree: Which API for Which Need
| Need | API |
|---|---|
| Spring physics with bounce / overshoot | `MotionScheme.expressive()` (M3 Expressive) |
| Pixel-level shader | `RuntimeShader` + `Modifier.graphicsLayer { renderEffect = ... }` (Android 13+) |
| Generative drawing (paths, particles, fractals) | `Canvas { drawScope -> ... }` |
| GPU effects (blur, shadows, color filters) | `Modifier.graphicsLayer { renderEffect = ... }` or `Modifier.blur(...)` |
| Adaptive system materials (Material You glassmorphism) | `Modifier.background(MaterialTheme.colorScheme.surfaceContainerHighest)` |
| Liquid glass on Android | AGSL shader recipe (no native API like iOS yet) |
---
## Domain 1: Material 3 Expressive
### What It Is
The 2025 Material 3 evolution introduces spring-based motion physics replacing fixed-duration tweens. New shape morphing API via `androidx.graphics.shapes`. New `MotionScheme` selectable on the theme. Aimed at hero moments, key interactions, brand-defining UI.
### MotionScheme
| Scheme | Personality | Use For |
|---|---|---|
| `MotionScheme.standard()` | Calmer, less overshoot | Default for chrome, lists, navigation |
| `MotionScheme.expressive()` | More overshoot, longer settle | Hero reveals, FABs, primary CTAs |
Apply on the theme:
```kotlin
MaterialTheme(motionScheme = MotionScheme.expressive()) {
// children read tokens via MaterialTheme.motionScheme.*
}
```
Tokens exposed:
| Token | Domain | Speed |
|---|---|---|
| `fastSpatialSpec()` | Position / size | < 200ms |
| `defaultSpatialSpec()` | Position / size | ~ 350ms |
| `slowSpatialSpec()` | Position / size | ~ 600ms |
| `fastEffectsSpec()` | Opacity / color | < 150ms |
| `defaultEffectsSpec()` | Opacity / color | ~ 250ms |
| `slowEffectsSpec()` | Opacity / color | ~ 400ms |
> **Spatial vs Effects:** spatial = anything physical (height, offset, scale). Effects = visual properties without inertia (alpha, color, elevation). Springs feel natural for spatial; tweens feel right for effects. The tokens encode this for you.
### Hero Card Expand (Expressive Springs)
```kotlin
@Composable
fun ExpressiveHero() {
var expanded by remember { mutableStateOf(false) }
MaterialTheme(motionScheme = MotionScheme.expressive()) {
val transition = updateTransition(targetState = expanded, label = "expand")
val height by transition.animateDp(
transitionSpec = { MaterialTheme.motionScheme.slowSpatialSpec() },
label = "height"
) { if (it) 400.dp else 100.dp }
val alpha by transition.animateFloat(
transitionSpec = { MaterialTheme.motionScheme.defaultEffectsSpec() },
label = "alpha"
) { if (it) 1f else 0f }
Card(
modifier = Modifier
.fillMaxWidth()
.height(height)
.clickable { expanded = !expanded }
) {
Box(modifier = Modifier.alpha(alpha)) {
Text("Detail content", modifier = Modifier.padding(24.dp))
}
}
}
}
```
### Spring Tuning Recipes
| Mood | Spec |
|---|---|
| Hero reveal | `spring(stiffness = Spring.StiffnessLow, dampingRatio = Spring.DampingRatioMediumBouncy)` |
| Snappy expressive | `spring(stiffness = Spring.StiffnessMediumLow, dampingRatio = 0.7f)` |
| Calm spatial | `MaterialTheme.motionScheme.defaultSpatialSpec()` (use the token) |
| Critical (no overshoot) | `spring(stiffness = Spring.StiffnessHigh, dampingRatio = 1f)` |
### Shape Morphing (M3 Expressive 1.3+)
`androidx.graphics.shapes` ships predefined morphable shapes (`MaterialShapes.Circle`, `Pentagon`, `Cookie4Sided`, `Sunny`, `Heart`, etc.) and a `Morph(start, end)` interpolator.
```kotlin
val morph = remember { Morph(MaterialShapes.Circle, MaterialShapes.Cookie4Sided) }
val progress by animateFloatAsState(
targetValue = if (active) 1f else 0f,
animationSpec = MaterialTheme.motionScheme.slowSpatialSpec(),
label = "morph"
)
Box(
modifier = Modifier
.size(96.dp)
.clip(GenericShape { size, _ ->
addPath(
morph.toPath(progress).asAndroidPath().asComposePath()
)
})
.background(MaterialTheme.colorScheme.primary)
)
```
### When to Use Expressive vs Standard
- **Expressive:** hero moments, key interactions, FABs, primary CTAs. 1-3% of UI.
- **Standard:** default for the rest of the app. Mixing too much Expressive feels chaotic - every element fighting for attention.
---
## Domain 2: AGSL Shaders (Android 13+)
### What It Is
AGSL is Android's shader language. Similar to GLSL with simplifications (`half4` instead of `vec4`, restricted feature set, sandbox-safe). `RuntimeShader` compiles your AGSL source. Bind to a Compose modifier via `Modifier.graphicsLayer { renderEffect = ... }`.
### Setup
```kotlin
@Composable
fun ShaderEffect(content: @Composable () -> Unit) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
// Android 12 and below: skip the shader, render content as-is.
content()
return
}
val shader = remember { RuntimeShader(AGSL_SOURCE) }
val time by produceState(0f) {
while (true) {
withFrameMillis { ms ->
value = ms / 1000f
}
}
}
Box(
modifier = Modifier
.onSizeChanged {
shader.setFloatUniform("resolution", it.width.toFloat(), it.height.toFloat())
}
.graphicsLayer {
shader.setFloatUniform("time", time)
renderEffect = RenderEffect
.createRuntimeShaderEffect(shader,Algorithmic and generative art with Canvas 2D - particles, flow fields, noise, fractals, L-systems.
Jetpack Compose animation foundations - animate*AsState, AnimatedVisibility, Crossfade, updateTransition, SharedTransitionLayout, gestures.
Compose Multiplatform / KMP patterns - expect/actual composables, platform-specific code, density and font handling cross-target, iOS/Android/Desktop interop.
Zero-dependency animations and visual techniques - scroll-driven, View Transitions, @starting-style, modern CSS.
Design audit checklist - motion gaps, accessibility, color consistency, responsive, performance.
Desktop-specific UX principles - hover states, pointer precision, keyboard shortcuts, multi-window, focus management. Covers macOS, Windows, Linux, web desktop.
Framer Motion / Motion sub-skill - AnimatePresence, layout animations, gestures, motion values.
GSAP animation engine sub-skill - core, timeline, ScrollTrigger, plugins.