compose-graphics
Advanced Compose visuals - Material 3 Expressive motion physics, AGSL shaders (Android 13+), Canvas/DrawScope generative, graphicsLayer effects.
Install / Use
npx skills add AThevon/genjutsu --skill compose-graphicsInstalls into whichever agent you are using.
SKILL.md
Installable skill definition
Quality Score
Category
DesignSupported Platforms
Our assessment of compose-graphics
compose-graphics scores 91/100 on our quality scale, 81st of 251 Design skills we index (top 33%).
Its SKILL.md is 20 KB long, well organised into 30 sections with 16 code examples: a thorough specification that gives an agent plenty to work with.
It has 370 GitHub stars, a meaningful sign that others use it.
Maintenance, license and trust
- The repository was last updated 26 days ago, so compose-graphics is actively maintained.
- No license is declared. By default that means all rights are reserved: you can read it, but reusing or redistributing it is not clearly permitted. Ask the author before building on it commercially.
- Its trust signals score 88/100, with 1 caution from licensing, adoption, age or documentation. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
Safety scan
No issues foundOur scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands.
Automated pattern scan on 2026-10-05. It catches known dangerous patterns, not every risk — read a skill before letting an agent act on it.
compose-graphics compared with similar skills
All 4 of these similar skills score higher than compose-graphics; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| compose-graphics (this skill)by AThevon | 91 | 370 | 26d ago | SKILL.md |
| Agent-Reachby Panniantong | 100 | 90.8k | 19d ago | CLAUDE.md |
| headroomby headroomlabs-ai | 100 | 74.4k | today | CLAUDE.md |
| Scraplingby D4Vinci | 100 | 85.7k | today | MCP Server |
| crawl4aiby unclecode | 100 | 84.8k | 9d ago | MCP Server |
Frequently asked questions
- How do I install compose-graphics?
- Run
npx skills add AThevon/genjutsu --skill compose-graphics. The install tabs above show the steps for each supported agent. - Which AI agents does compose-graphics work with?
- It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
- Is compose-graphics safe to use?
- Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. It declares no license and scores 88/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is compose-graphics still maintained?
- The repository was last updated 26 days ago, so compose-graphics is actively maintained.
Skill content
View source on GitHubname: compose-graphics description: "Advanced Compose visuals - Material 3 Expressive motion physics, AGSL shaders (Android 13+), Canvas/DrawScope generative, graphicsLayer effects." metadata: internal: true
Version-sensitive. Every API name, SDK gate and browser-support claim below was verified on 2026-09-08 against primary sources. What against, and when, is in
_jutsu/VERSIONS.md. If that date is old, re-verify before acting on a version number.
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.mdcovers basics. Concise rules here. Deep-dive inreferences/.
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:
MaterialTheme(motionScheme = MotionScheme.expressive()) {
// children read tokens via MaterialTheme.motionScheme.*
}
Tokens exposed:
| Token | Domain | Spring (damping / stiffness) - standard | ... expressive |
|---|---|---|---|
| fastSpatialSpec() | Position / size | 0.9 / 1400 | 0.6 / 800 |
| defaultSpatialSpec() | Position / size | 0.9 / 700 | 0.8 / 380 |
| slowSpatialSpec() | Position / size | 0.9 / 300 | 0.8 / 200 |
| fastEffectsSpec() | Opacity / color | 1.0 / 3800 | 1.0 / 3800 |
| defaultEffectsSpec() | Opacity / color | 1.0 / 1600 | 1.0 / 1600 |
| slowEffectsSpec() | Opacity / color | 1.0 / 800 | 1.0 / 800 |
Spatial vs Effects: spatial = anything physical (height, offset, scale). Effects = visual properties without inertia (alpha, color, elevation). Both families are springs - the effects ones are just critically damped (
dampingRatio = 1.0) and much stiffer, so they never overshoot. Only the spatial springs differ betweenstandard()andexpressive().
Availability:
MotionScheme,MaterialTheme(motionScheme = ...)andMaterialExpressiveThemeare stable in material3 1.4.0 (no opt-in needed).MaterialShapesand the shape-morphing helpers are not - they need 1.5.0-alpha and@OptIn(ExperimentalMaterial3ExpressiveApi::class).
Hero Card Expand (Expressive Springs)
@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 (MaterialShapes + Morph)
Two different libraries, and the split matters:
androidx.graphics.shapes:graphics-shapes(stable 1.1.0) shipsRoundedPolygon,CornerRoundingandMorph(start, end). ItsMorph.toPath(progress)returns anandroid.graphics.Path.- The predefined Material shapes (
MaterialShapes.Circle,Pentagon,Cookie4Sided,Sunny,Heart, ...) live in material3, not in graphics-shapes. They are still@ExperimentalMaterial3ExpressiveApiand ship only inandroidx.compose.material3:material3:1.5.0-alpha*- they are not in stable material3 1.4.0. material3 also addsMorph.toPath(progress)returning a ComposePath, plusRoundedPolygon.toShape().
Never write .asAndroidPath().asComposePath(): with the graphics-shapes import it does not compile (android.graphics.Path has no asAndroidPath()), and with the material3 import it is a pointless round trip. And because MaterialShapes are normalized to a 0..1 box, the path must be scaled to the draw size - dropping the raw path into GenericShape yields a ~1px shape in the top-left corner.
import androidx.compose.material3.MaterialShapes
import androidx.compose.material3.toPath // Morph.toPath -> androidx.compose.ui.graphics.Path
import androidx.graphics.shapes.Morph
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun MorphingBadge(active: Boolean) {
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(MorphShape(morph, progress))
.background(MaterialTheme.colorScheme.primary)
)
}
/** MaterialShapes are normalized to 0..1: scale the path to the draw size, then centre it. */
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
private class MorphShape(private val morph: Morph, private val progress: Float) : Shape {
override fun createOutline(
size: Size,
layoutDirection: LayoutDirection,
density: Density,
): Outline {
val path = morph.toPath(progress = progress)
path.transform(Matrix().apply { scale(x = size.width, y = size.height) })
path.translate(size.center - path.getBounds().center)
return Outline.Generic(path)
}
}
For a static (non-morphing) shape, skip all of this: MaterialShapes.Cookie4Sided.toShape() returns a ready-to-use Shape that already handles the scaling.
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
@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, "image")
.asComposeRenderEffect()
}
) { content() }
}
Always gate on
Build.VERSION.SDK_INT >= 33. Pre-Android 13 fallback: render the content unmodified, or useModifier.blur()/ a static gradient overlay.
Recipe: Touch Ripple
AGSL source:
// ripple.agsl
uniform float2 resolution;
uniform float2 origin;
uniform float time;
uniform shader image;
half4 main(float2 fragCoord) {
float2 toOrigin = fragCoord - origin;
float dist = length(toOrigin);
float wave = sin(dist * 0.05 - time * 8.0) * 0.05;
float falloff = 1.0 / max(dist * 0.01, 1.0);
float2 dir = toOrigin / max(dist, 0.0001);
float2 displaced = fragCoord + dir * wave * falloff * 50.0;
return image.eval(displaced);
}
Compose binding (state-driven time, animated via LaunchedEffect):
@Composable
fun RippleSurface(content: @Composable BoxScope.() -> Unit) {
if (Build.VERSION.SDK_INT < 33) { Box { content() }; return }
val shader = remember { RuntimeShader(RIPPLE_AGSL) }
var origin by remember { mutableStateOf(Offset.Zero) }
var startMs by remember { mutableStateOf<Long?>(null) }
val time by produceState(0f, startMs) {
if (startMs == null) { value = 0f; return@produceState }
val begin = startMs!!
while (true) {
withFrameMillis { now ->
value = (now - begin) / 1000f
}
}
}
Box(
modifier = Modifier
.onSizeChanged {
shader.setFloatUniform("resolution", it.width.toFloat(), it.height.toFloat())
}
.pointerInput(Unit) {
detectTapGestures { tap ->
origin = tap
startMs = System.currentTimeMillis()
}
}
.graphicsLayer {
shader.setFloatUniform("origin", origin.x, origin.y)
shader.setFloatUniform("time", time)
renderEffect = RenderEffect
.createRuntimeShaderEffect(shader, "image")
.asComposeRenderEffect()
},
content = content
)
}
Recipe: Holographic Gradient
uniform float time;
uniform shader image;
half4 main(float2 fragCoord) {
half4 color = image.eval(fragCoord);
float n = fragCoord.x * 0.01 + fragCoord.y * 0.005 + time * 0.3;
half3 rainbow = half3(
sin(n * 2.0) * 0.5 + 0.5,
sin(n * 2.0 + 2.094) * 0.5 + 0.5,
sin(n * 2.0 + 4.188) * 0.5 + 0.5
);
half luma = dot(color.rgb, half3(0.299, 0.587, 0.114));
return half4(mix(color.rgb, rainbow * luma * 2.0, 0.5), color.a);
}
Multiplies the underlying view's luminance by a phase-shifted RGB sine wave - shimmer over text or icons. time animates the wave drift.
Recipe: Liquid Glass / Glassmorphism
Android lacks a native iOS-26-style glassEffect. Compose this with blur + chromatic aberration + soft edge tint:
uniform float2 resolution
Truncated for display — read the full file on GitHub.
Related Skills
Agent-Reach
90.8kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
headroom
74.4kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
Scrapling
85.7k🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scrapling_dev
crawl4ai
84.8kOpen-source web crawler and scraper for LLMs and AI agents: any website into clean, LLM-ready Markdown. Run it yourself, or use Crawl4AI Cloud with one key.
Languages
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
