This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
mobilecritical PriorityID: compose-multiplatform-skiko-render-decoupling

Compose Multiplatform Skiko Main-Thread Render Lockstep Decoupling

Mandates strict separation between high-frequency gesture processing and Skiko Canvas rasterization pipelines in Compose Multiplatform. Prevents touch-latency spikes, thread starvation, and missed vsync deadlines on 120Hz ProMotion/LTPO mobile displays by enforcing draw-phase transformation and non-blocking snapshot updates.

Prohibited Anti-Pattern: Synchronous Canvas Invalidation and Path Allocation in Gesture Dispatch Loops

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Compose Multiplatform Skiko Main-Thread Render Lockstep Decoupling - Mandates strict separation between high-frequency gesture processing and Skiko Canvas rasterization pipelines in Compose Multiplatform. Prevents touch-latency spikes, thread starvation, and missed vsync deadlines on 120Hz ProMotion/LTPO mobile displays by enforcing draw-phase transformation and non-blocking snapshot updates.
globs: **/commonMain/**/*.kt, **/iosMain/**/*.kt, **/androidMain/**/*.kt
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/compose-multiplatform-skiko-render-decoupling"
---

# Compose Multiplatform Skiko Main-Thread Render Lockstep Decoupling

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Synchronous Canvas Invalidation and Path Allocation in Gesture Dispatch Loops

## System Constraints
You are a Principal Software Architect enforcing zero-jank Skiko rendering invariants in Compose Multiplatform mobile targets. On high-refresh-rate displays (90Hz/120Hz), the Skiko Metal/OpenGL render loop operates within strict 8.33ms frame budgets. You must strictly forbid synchronous CPU Canvas mutations, allocations in draw blocks, and state reads that cause continuous recomposition during pointer drag/scroll events. Ensure all gesture transformations run exclusively within isolated draw-phase graphicsLayer mutations.

## Strict Guidelines
- Engineers MUST ALWAYS defer state reads during gestures to the draw phase using lambda-based Modifier.graphicsLayer { translationX = ... } to bypass recomposition and layout phases.
- Engineers MUST NOT allocate Skiko Canvas, Path, Paint, or Shader objects inside DrawScope, Canvas, or pointerInput lambdas; pre-allocate and reuse them across frames.
- Code SHOULD buffer high-frequency pointer input deltas using conflated channels or Animatable instances instead of triggering synchronous multiplatform snapshot notifications on every touch packet.
- Services MUST route complex Skia software path operations off the UI dispatcher and cache rasterized textures in an ImageBitmap or Skia Image before rendering.
- Components NEVER couple UIKit or Android platform touch event callbacks directly with synchronous Skiko render queue flushes.

## Bad vs Good Implementations
### Gesture Handling with GraphicsLayer vs Recomposition

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Mutating mutableStateOf inside high-frequency pointer input forces Compose to invalidate and recompose the component every frame. This triggers layout passes and couples touch events directly with Skiko Canvas recreation on the main thread, leading to dropped frames on 120Hz displays.
```kotlin
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.offset
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.IntOffset
import kotlin.math.roundToInt

@Composable
fun DraggableCardBad() {
    // ANTI-PATTERN: Direct recomposition state read on high-refresh-rate pointer loop.
    // Triggers full recomposition, relayout, and Skiko raster invalidation every 8ms.
    var offsetX by remember { mutableStateOf(0f) }
    var offsetY by remember { mutableStateOf(0f) }

    Box(
        Modifier
            .offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }
            .pointerInput(Unit) {
                detectDragGestures {
 change, dragAmount ->
                    change.consume()
                    offsetX += dragAmount.x
                    offsetY += dragAmount.y
                }
            }
    )
}
```

#### Production Standard (Correct)
> **Standard**: Reading offset values inside the graphicsLayer lambda isolates updates to the Compose draw phase. Skiko updates the underlying Metal/OpenGL render matrix directly without re-invoking recomposition or CPU layout calculations, maintaining a consistent 120fps budget.
```kotlin
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.VectorConverter
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import kotlinx.coroutines.launch

@Composable
fun DraggableCardGood() {
    // PRODUCTION FIX: Isolates translation updates to the GPU draw phase.
    // Skips recomposition and layout entirely; updates Skiko render matrix directly.
    val offset = remember { Animatable(Offset.Zero, Offset.VectorConverter) }
    val coroutineScope = rememberCoroutineScope()

    Box(
        Modifier
            .graphicsLayer {
                translationX = offset.value.x
                translationY = offset.value.y
            }
            .pointerInput(Unit) {
                detectDragGestures {
 change, dragAmount ->
                    change.consume()
                    coroutineScope.launch {
                        offset.snapTo(offset.value + dragAmount)
                    }
                }
            }
    )
}
```

Recommended Agent Skills (askills.dev)

Ready-to-use executable skill functions tailored to this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Compose Multiplatform Skiko Main-Thread Render Lockstep Decoupling

Compose Multiplatform Skiko Main-Thread Render Lockstep Decoupling defines an industrial-grade behavioral standard for mobile engineering. Mandates strict separation between high-frequency gesture processing and Skiko Canvas rasterization pipelines in Compose Multiplatform. Prevents touch-latency spikes, thread starvation, and missed vsync deadlines on 120Hz ProMotion/LTPO mobile displays by enforcing draw-phase transformation and non-blocking snapshot updates. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Synchronous Canvas Invalidation and Path Allocation in Gesture Dispatch Loops Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftSynchronous Canvas Invalidation and Path Allocation in Gesture Dispatch LoopsCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST ALWAYS defer state reads during gestures to the draw phase using lambda-based Modifier.graphicsLayer { translationX = ... } to bypass recomposition and layout phases.

Engineers MUST ALWAYS defer state reads during gestures to the draw phase using lambda-based Modifier.graphicsLayer { translationX = ... } to bypass recomposition and layout phases.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NOT allocate Skiko Canvas, Path, Paint, or Shader objects inside DrawScope, Canvas, or pointerInput lambdas

Engineers MUST NOT allocate Skiko Canvas, Path, Paint, or Shader objects inside DrawScope, Canvas, or pointerInput lambdas; pre-allocate and reuse them across frames.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Code SHOULD buffer high-frequency pointer input deltas using conflated channels or Animatable instances instead of triggering synchronous multiplatform snapshot notifications on every touch packet.

Code SHOULD buffer high-frequency pointer input deltas using conflated channels or Animatable instances instead of triggering synchronous multiplatform snapshot notifications on every touch packet.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Services MUST route complex Skia software path operations off the UI dispatcher and cache rasterized textures in an ImageBitmap or Skia Image before rendering.

Services MUST route complex Skia software path operations off the UI dispatcher and cache rasterized textures in an ImageBitmap or Skia Image before rendering.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Components NEVER couple UIKit or Android platform touch event callbacks directly with synchronous Skiko render queue flushes.

Components NEVER couple UIKit or Android platform touch event callbacks directly with synchronous Skiko render queue flushes.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is Compose Multiplatform Skiko Main-Thread Render Lockstep Decoupling critical for AI coding assistants?

Mandates strict separation between high-frequency gesture processing and Skiko Canvas rasterization pipelines in Compose Multiplatform. Prevents touch-latency spikes, thread starvation, and missed vsync deadlines on 120Hz ProMotion/LTPO mobile displays by enforcing draw-phase transformation and non-blocking snapshot updates. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Synchronous Canvas Invalidation and Path Allocation in Gesture Dispatch Loops) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

Related MOBILE Rules

View all rules →
1 Rule in Stack

Compose