Agent Skills
› android/skills
› ink-custom-brush-builder
ink-custom-brush-builder
GitHub用于在Android应用中通过Jetpack Ink API创建自定义画笔。支持配置笔刷形状、压力感应、多层渲染及纹理贴图,生成完整的Kotlin BrushFamily实现代码。
Trigger Scenarios
创建自定义BrushFamily定义
配置BrushTip形状和BrushBehavior节点图
设置SlidingWindowModel输入平滑
序列化或反序列化画笔
Install
npx skills add android/skills --skill ink-custom-brush-builder -g -y
SKILL.md
Frontmatter
{
"name": "ink-custom-brush-builder",
"license": "Complete terms in LICENSE.txt",
"metadata": {
"author": "Google LLC",
"keywords": [
"Android",
"Jetpack Ink",
"androidx.ink",
"BrushFamily",
"BrushCoat",
"BrushTip",
"BrushPaint",
"BrushBehavior",
"TilingTexture",
"StampingTexture",
"ColorFunction",
"SlidingWindowModel",
"custom brush"
],
"last-updated": "2026-10-28"
},
"description": "Creates custom BrushFamily definitions for an Android app using Jetpack Ink (androidx.ink 1.1.0-alpha03 and higher). Use this skill when configuring custom BrushTip shapes, adding pressure, tilt, speed, or noise sensitivity using BrushBehavior node graphs, creating multi-coat layered brushes, applying tiling or particle stamping textures, configuring SlidingWindowModel input smoothing, or serializing brushes. Delivers complete Kotlin BrushFamily, BrushCoat, BrushTip, BrushPaint, and BrushBehavior implementations. Don't use for View-based (XML) inking, Compose drawing surface setup, or stock brush selection. For Compose drawing surface setup, InProgressStrokes wet and dry rendering, eraser, or persistence, suggest the ink-app-builder skill."
}
Custom brushes in the Android Ink API are built around the BrushFamily
hierarchy:
BrushFamily
├── InputModel (BrushFamily.InputModel.SlidingWindowModel or PASSTHROUGH_MODEL)
└── BrushCoat[] (one or more rendering layers)
├── BrushTip (shape: scaleX, scaleY, cornerRounding, rotationDegrees, slantDegrees, pinch)
│ └── BrushBehavior[] (dynamic response to stylus or touch input)
│ └── Tree: TargetNode(input = [Operators](input = SourceNode))
└── BrushPaint (visual appearance)
├── SelfOverlap (ANY, ACCUMULATE, or DISCARD)
├── TextureLayer[] (BrushPaint.TilingTexture or BrushPaint.StampingTexture)
└── BrushPaint.ColorFunction[] (OpacityMultiplier or ReplaceColor)
Create a Brush by combining a custom BrushFamily with a Compose Color,
size, and epsilon:
val brush = Brush.createWithComposeColor(
family = myCustomFamily,
color = Color.Black,
size = 10f,
epsilon = 0.1f,
)
Version and experimental API requirements :
- Requires
androidx.ink1.1.0-alpha03and higher : In1.0.0(Stable) and1.1.0-alpha01-alpha02,BrushFamily(...),BrushCoat,BrushTip,BrushPaint,BrushBehavior, andandroidx.ink.brush.behavior.*nodes were@RestrictTo(LIBRARY_GROUP)(in1.0.0stable, custom brushes can only be loaded from binary proto streams usingBrushFamily.decode). Starting in1.1.0-alpha03and higher , programmatic custom brush constructors graduated to public API (BrushPaint.TilingTexture,BrushPaint.StampingTexture,BrushPaint.ColorFunction,BrushFamily.InputModel.SlidingWindowModel, and all behavior nodes).- No
@OptInrequired in1.1.0-alpha03and higher : All public custom brush classes andink-storageBrushFamilyserialization APIs (BrushFamily.encodeanddecode,AndroidBrushFamilySerialization,BrushFamilyDecodeCallback) are unannotated in1.1.0-alpha03and higher (ExperimentalInkCustomBrushApiis@RestrictTo(LIBRARY_GROUP)in1.1.0-alpha05and higher, and is only required onBrushFamilyserialization in1.0.0stable).
Workflow and task routing
Follow these conditional instructions based on the requested custom brush task:
- Step 1 (Dependencies) : When setting up an Android project for programmatic custom brushes, ask user permission before editing build files and verify that
androidx.ink:ink-brush,androidx.ink:ink-brush-compose,androidx.ink:ink-storage, andandroidx.ink:ink-nativeloaderuse version1.1.0-alpha03or higher ingradle/libs.versions.tomlandapp/build.gradle.kts. - Step 2 (Hierarchy, tip shape, paint, and input smoothing) : When defining
BrushFamilyand multi-coatBrushCoatlayers, configuringBrushTipgeometry (scaleX,scaleY,cornerRounding,rotationDegrees,slantDegrees,pinch), settingBrushPaintproperties (SelfOverlap,ColorFunction), or smoothing stroke input withBrushFamily.InputModel.SlidingWindowModel, you MUST follow brush-structure.md. For baselineBrushcreation or1.0.0resource loading, review Brush APIs. - Step 3 (Dynamic stylus and touch behaviors) : When making a brush respond dynamically to stylus pressure, tilt, speed, direction, or procedural noise using
BrushBehaviornode trees (SourceNode,DampingNode,NoiseNode,ResponseNode,TargetNode,PolarTargetNode), you MUST follow brush-behaviors.md. - Step 4 (Textures and serialization) : When adding
BrushPaint.TilingTextureorBrushPaint.StampingTexturelayers, implementingTextureBitmapStore, or encoding and decoding customBrushFamilydefinitions (BrushFamily.encodeanddecode,AndroidBrushFamilySerialization,BrushFamilyDecodeCallback), you MUST follow textures-and-serialization.md. Inform the user which texture image files (such asapp/src/main/res/drawable-nodpi/pencil_grain.png) to add to their project and register inTextureBitmapStore. - Step 5 (Complete brush recipes) : When building a complete pressure pen, calligraphy nib, shading pencil, watercolor wash, or multi-coat shadow brush from scratch, start from the copy-ready implementations in examples.md.
- Compose drawing surface, eraser, or persistence : For Compose drawing surface setup,
InProgressStrokeswet and dry rendering, geometry-based erasing, or Room stroke persistence, suggest theink-app-builderskill.
Antipatterns
- NEVER use raw
ink.proto.*builders to construct brushes---always use the public Kotlin constructors (BrushFamily,BrushCoat,BrushTip,BrushPaint,BrushBehaviorfromandroidx.ink.brush.*). - NEVER manually scale stroke width in a touch listener for pressure or tilt sensitivity---use
BrushBehaviormappingSourceNode.Source.NORMALIZED_PRESSUREorTILT_IN_RADIANStoTargetNode.Target.SIZE_MULTIPLIERorWIDTH_MULTIPLIER. - NEVER use manual
Canvasbitmap stamping orBitmapShaderfor textured brushes---useBrushPaint.TilingTextureorBrushPaint.StampingTexturewith aTextureBitmapStore. - NEVER use
BlendMode.SRC_OVERon the final (or only)TextureLayer---useBlendMode.MODULATE,DST_IN,DST_OUT,SRC_ATOP, orSRC_INso edge anti-aliasing andOPACITY_MULTIPLIERbehaviors aren't overridden. - NEVER serialize
BrushFamilyas JSON, Gson, Moshi, orParcelable---always useBrushFamily.encodeandBrushFamily.decodeorAndroidBrushFamilySerializationfromandroidx.ink.storage. - NEVER implement manual Bézier (
quadTo,cubicTo) smoothing ---configureBrushFamily.InputModel.SlidingWindowModelfor input smoothing andDampingNodefor behavior smoothing. - NEVER use
Random.nextFloatin draw loops for organic stroke wobble---attach aNoiseNodevaried over stroke distance inBrushBehavior.
Version History
- 6daa53e Current 2026-11-02 23:10


