{"slug":"mobile-animation-skia","title":"mobile-animation-skia","summary":"React Native Skia GPU-accelerated 2D graphics - Canvas, declarative drawing, shaders, image filters, Paragraph text, Atlas batch rendering, Reanimated animations","platform":"Claude","tags":[],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-09-29T15:28:12.797657Z","repo":{"url":"https://github.com/agents-inc/skills","stars":24,"forks":8,"license":"MIT","updatedAt":"2026-09-07T17:50:55Z"},"bodyHtml":"<hr>\n<h2>name: mobile-animation-skia\ndescription: React Native Skia GPU-accelerated 2D graphics - Canvas, declarative drawing, shaders, image filters, Paragraph text, Atlas batch rendering, Reanimated animations</h2>\n<h1>React Native Skia Patterns</h1>\n<blockquote>\n<p><strong>Quick Guide:</strong> Use <code>@shopify/react-native-skia</code> for GPU-accelerated 2D drawing in React Native. The Canvas component hosts a separate React renderer. Drawing primitives (Circle, Rect, Path, Image) compose declaratively. Paint attributes cascade through Groups. Animations use Reanimated shared values passed directly as props -- no <code>createAnimatedComponent</code> needed. Use <code>interpolateColors</code> from Skia for color animations (not Reanimated's <code>interpolateColor</code>). Use Atlas for batch rendering thousands of sprites. Use Paragraph for rich text layout. Group transforms default to top-left origin, not center.</p>\n</blockquote>\n<hr>\n<p>&lt;critical_requirements&gt;</p>\n<h2>CRITICAL: Before Using This Skill</h2>\n<blockquote>\n<p><strong>All code must follow project conventions in CLAUDE.md</strong> (kebab-case, named exports, import ordering, <code>import type</code>, named constants)</p>\n</blockquote>\n<p><strong>(You MUST pass Reanimated shared values directly as Skia component props -- do NOT use createAnimatedComponent or useAnimatedProps)</strong></p>\n<p><strong>(You MUST use <code>interpolateColors</code> from <code>@shopify/react-native-skia</code> for color animations -- Reanimated's <code>interpolateColor</code> uses a different internal color format and produces wrong results)</strong></p>\n<p><strong>(You MUST use the <code>layer</code> property to apply paint effects to Paragraph, Picture, and ImageSVG components -- they do not follow standard paint inheritance rules)</strong></p>\n<p><strong>(You MUST remember that Group transform origin defaults to top-left, not center -- set <code>origin</code> prop explicitly for center-based rotations)</strong></p>\n<p>&lt;/critical_requirements&gt;</p>\n<hr>\n<p><strong>Auto-detection:</strong> react-native-skia, @shopify/react-native-skia, Canvas, Skia.Path, Skia.Paint, Circle, Rect, Path, Group, Paint, ImageSVG, BackdropBlur, BackdropFilter, RuntimeShader, Atlas, Paragraph, ParagraphBuilder, usePathInterpolation, useClock, useRSXformBuffer, SkSL, image filter, shader, offscreen, Picture, FitBox</p>\n<p><strong>When to use:</strong></p>\n<ul>\n<li>Drawing custom 2D graphics (charts, diagrams, custom shapes)</li>\n<li>Applying GPU-accelerated blur, shadow, or color filter effects</li>\n<li>Animating paths, shapes, or shader uniforms at 60 FPS</li>\n<li>Rendering rich text with mixed fonts using Paragraph API</li>\n<li>Batch rendering sprites/tiles with Atlas</li>\n<li>Creating custom image filters with SkSL shaders</li>\n<li>Generating images offscreen (thumbnails, exports)</li>\n</ul>\n<p><strong>When NOT to use:</strong></p>\n<ul>\n<li>Standard UI layouts (use regular React Native views)</li>\n<li>Simple static images (use <code>&lt;Image&gt;</code> from React Native)</li>\n<li>3D graphics (Skia is 2D only -- use a 3D solution)</li>\n<li>Text-only screens (use React Native <code>&lt;Text&gt;</code>)</li>\n</ul>\n<p><strong>Key patterns covered:</strong></p>\n<ul>\n<li>Canvas setup and threading model</li>\n<li>Declarative drawing with shapes, paths, and images</li>\n<li>Paint inheritance and composition through Groups</li>\n<li>Reanimated integration (shared values as props, color interpolation)</li>\n<li>Image filters (Blur, Shadow, RuntimeShader) and backdrop filters</li>\n<li>Paragraph text layout with custom fonts</li>\n<li>Atlas batch rendering for sprites and tiles</li>\n<li>SkSL custom shaders with uniforms</li>\n<li>Picture recording for dynamic drawing operations</li>\n<li>SVG rendering with limitations</li>\n</ul>\n<p><strong>Detailed Resources:</strong></p>\n<ul>\n<li><a href=\"examples/core.md\">examples/core.md</a> - Canvas, shapes, paths, paint, groups, images</li>\n<li><a href=\"examples/animations.md\">examples/animations.md</a> - Reanimated integration, path interpolation, color animation, Atlas animation</li>\n<li><a href=\"examples/effects.md\">examples/effects.md</a> - Image filters, backdrop blur, shaders, RuntimeShader</li>\n<li><a href=\"examples/text-and-media.md\">examples/text-and-media.md</a> - Paragraph API, SVG rendering, Picture recording, offscreen rendering</li>\n<li><a href=\"reference.md\">reference.md</a> - Decision frameworks, paint property reference, SkSL types</li>\n</ul>\n<hr>\n\n<hr>\n\n<hr>\n<p>&lt;decision_framework&gt;</p>\n<h2>Decision Framework</h2>\n<h3>When to Use Skia vs Native Views</h3>\n<pre><code>Does the feature need custom drawing (paths, gradients, blur, shaders)?\n├─ YES → Skia Canvas\n└─ NO → Does it need high-performance batch rendering (100+ similar elements)?\n    ├─ YES → Skia Atlas\n    └─ NO → Does it need rich text with mixed fonts/decorations?\n        ├─ YES → Skia Paragraph (or native Text if simple)\n        └─ NO → Standard React Native views\n</code></pre>\n<h3>Declarative vs Imperative API</h3>\n<pre><code>Is the shape/path static or defined at build time?\n├─ YES → Declarative JSX (&lt;Circle /&gt;, &lt;Path path=\"...\" /&gt;)\n└─ NO → Is the shape computed dynamically per frame?\n    ├─ YES → Imperative (Skia.Path.Make()) inside worklets or useDerivedValue\n    └─ NO → Is the shape created once based on data?\n        ├─ YES → Imperative, created outside render, passed as prop\n        └─ NO → Declarative with animated shared value props\n</code></pre>\n<h3>Choosing the Right Text API</h3>\n<pre><code>Need simple single-style text?\n├─ YES → Skia &lt;Text&gt; component (single font, single style)\n└─ NO → Need mixed fonts, weights, or line breaking?\n    ├─ YES → Paragraph API (ParagraphBuilder)\n    └─ NO → Need text on a path?\n        ├─ YES → &lt;TextPath&gt; component\n        └─ NO → &lt;Text&gt; with Glyphs for advanced positioning\n</code></pre>\n<p>&lt;/decision_framework&gt;</p>\n<hr>\n<p>&lt;red_flags&gt;</p>\n<h2>RED FLAGS</h2>\n<p><strong>High Priority Issues:</strong></p>\n<ul>\n<li>Using <code>createAnimatedComponent</code> or <code>useAnimatedProps</code> with Skia components -- unnecessary; pass shared values directly as props</li>\n<li>Using Reanimated's <code>interpolateColor</code> for Skia color animations -- produces wrong colors; use <code>interpolateColors</code> from <code>@shopify/react-native-skia</code></li>\n<li>Applying paint children (Shader, Blur) directly to Paragraph, Picture, or ImageSVG -- they ignore standard paint inheritance; use the <code>layer</code> property</li>\n<li>Using ScrollView with map() to render many Skia shapes -- use Atlas for batch rendering, or Picture for dynamic draw counts</li>\n<li>Performing heavy computations in Canvas children on JS thread -- offload to worklets or <code>useDerivedValue</code> to keep animations on UI thread</li>\n</ul>\n<p><strong>Medium Priority Issues:</strong></p>\n<ul>\n<li>Not setting <code>origin</code> on Group transforms and expecting center-based rotation -- default is top-left</li>\n<li>RuntimeShader ignoring pixel density -- content appears blurry on high-DPI screens; wrap in a scale layer (scale by <code>PixelRatio.get()</code>, then scale back by <code>1/pd</code>)</li>\n<li>Creating new Path objects every render -- memoize or use <code>usePathValue</code> to avoid garbage collection pressure</li>\n<li>Hardcoding Canvas dimensions instead of using <code>onSize</code> shared value or <code>useCanvasSize</code> -- breaks on different screen sizes</li>\n<li>Missing <code>androidWarmup={true}</code> for opaque canvases -- first frame renders white on Android</li>\n</ul>\n<p><strong>Gotchas &amp; Edge Cases:</strong></p>\n<ul>\n<li>Canvas uses its own React renderer -- React context from outside the Canvas is NOT available inside it</li>\n<li><code>useCanvasSize</code> returns <code>{ width: 0, height: 0 }</code> on first render -- guard against zero dimensions</li>\n<li>ImageSVG does not render <code>&lt;text&gt;</code> elements, CSS styles, or <code>&lt;animate&gt;</code> -- preprocess SVGs with SVGO</li>\n<li><code>Skia.RuntimeEffect.Make()</code> returns null if the shader has syntax errors -- always handle the null case</li>\n<li>Atlas transforms are RSXform (rotation-scale-translation), not standard Transform2d -- use <code>Skia.RSXform()</code> or <code>Skia.RSXformFromRadians()</code></li>\n<li>Path interpolation requires paths with the same number and types of commands -- mismatched paths crash</li>\n<li><code>useImage</code> returns null while loading -- always guard rendering on image availability</li>\n<li>Bundle size impact: +6MB iOS, +4MB Android, +2.9MB web (CanvasKit WASM)</li>\n<li>React Native &gt;= 0.79 and React &gt;= 19 required for current versions (v1.12.4 for RN &lt;= 0.78)</li>\n<li>Canvas snapshot: use <code>makeImageSnapshotAsync()</code> for images with textures, <code>makeImageSnapshot()</code> only for texture-free drawings</li>\n<li><code>useFonts</code> returns null while fonts load -- guard Paragraph rendering until fonts are ready</li>\n</ul>\n<p>&lt;/red_flags&gt;</p>\n<hr>\n<p>&lt;critical_reminders&gt;</p>\n<h2>CRITICAL REMINDERS</h2>\n<blockquote>\n<p><strong>All code must follow project conventions in CLAUDE.md</strong></p>\n</blockquote>\n<p><strong>(You MUST pass Reanimated shared values directly as Skia component props -- do NOT use createAnimatedComponent or useAnimatedProps)</strong></p>\n<p><strong>(You MUST use <code>interpolateColors</code> from <code>@shopify/react-native-skia</code> for color animations -- Reanimated's <code>interpolateColor</code> uses a different internal color format and produces wrong results)</strong></p>\n<p><strong>(You MUST use the <code>layer</code> property to apply paint effects to Paragraph, Picture, and ImageSVG components -- they do not follow standard paint inheritance rules)</strong></p>\n<p><strong>(You MUST remember that Group transform origin defaults to top-left, not center -- set <code>origin</code> prop explicitly for center-based rotations)</strong></p>\n<p><strong>Failure to follow these rules will produce broken color animations, invisible paint effects, and incorrectly positioned rotations.</strong></p>\n<p>&lt;/critical_reminders&gt;</p>\n","files":[{"path":"examples/animations.md","sizeBytes":7186,"isText":true},{"path":"examples/core.md","sizeBytes":8312,"isText":true},{"path":"examples/effects.md","sizeBytes":8595,"isText":true},{"path":"examples/text-and-media.md","sizeBytes":8065,"isText":true},{"path":"reference.md","sizeBytes":5970,"isText":true},{"path":"SKILL.md","sizeBytes":19495,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"trusted-source-unreviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"trusted-source-unreviewed","screen":{"ran":true,"outcome":"clean","suspicious":0,"notes":0,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-09-29T15:30:57.66091Z","sha256":"02D8C92B3AF54E9CEE8A64A8BCB7E2DED6B122D39ECC536C3299F5474D078B2F","sizeBytes":20751},"review":null,"source":{"repositoryUrl":"https://github.com/agents-inc/skills","path":"dist/plugins/mobile-animation-skia/skills/mobile-animation-skia","license":"MIT","commit":"3a51ef571e996b18294bf776d53dbdad26de0617","subtreeSha":"8FD140000DE70FE03091EC2CDD92B8FB5728C47E387774C98FD01D29F5404731","lastSyncedAt":"2026-09-29T15:27:48.914434Z"},"reviewedAt":"2026-09-29T15:36:46.904503Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/agents-inc/skills/tree/main/dist/plugins/mobile-animation-skia/skills/mobile-animation-skia"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install agents-inc-skills@llmmart"},{"target":"git","command":"git clone https://github.com/agents-inc/skills.git"}]}