Summary
The core builder DSL embeds a compiled pattern with include(pattern) (dsl/HapticPatternScope.kt:175). The Compose DSL has no counterpart, so algebra results cannot be placed on a timeline next to inline nodes. Add one:
Jindong(speed) {
Sequence {
Clip(heartbeat.timeStretch(1f / speed))
Delay(200.ms)
Haptic(60.ms, HapticIntensity.MEDIUM)
}
}
Scope:
@Composable fun JindongScope.Clip(pattern: HapticPattern) in jindong-compose, wrapping the existing PatternElement. No core changes.
fun clip(pattern: HapticPattern) alias for include on HapticPatternScope, so both DSLs share one vocabulary. include stays as is.
Why "Clip"
Content-emitting composables are named with nouns, which rules out Include. Pattern is too generic: everything in this DSL is a pattern, and the name invites Pattern(Sequence { ... }) misreadings. A clip is a prebuilt, self-contained unit placed on a timeline, which is exactly what this node does, and the word cannot be mistaken for something that wraps inline content.
Semantics
The composition inside Jindong is single-shot: compilePattern composes once and disposes the host (Jindong.kt:120-127), so ComposeNode update blocks never re-run after insertion. Clip therefore follows the same idiom as every other node (value captured at compile time), and reactivity comes from threading the pattern through the trigger keys:
Jindong(pattern) { Clip(pattern) }
HapticPattern is a data class, so the key comparison is structural.
Acceptance criteria
- Compose UI tests (RecordingHapticExecutor idiom): a pattern threaded through keys re-fires with the new events; a pattern changed without a key does not.
apiDump regenerated for both modules.
Depends on #85 and #88.
Summary
The core builder DSL embeds a compiled pattern with
include(pattern)(dsl/HapticPatternScope.kt:175). The Compose DSL has no counterpart, so algebra results cannot be placed on a timeline next to inline nodes. Add one:Scope:
@Composable fun JindongScope.Clip(pattern: HapticPattern)in jindong-compose, wrapping the existingPatternElement. No core changes.fun clip(pattern: HapticPattern)alias forincludeonHapticPatternScope, so both DSLs share one vocabulary.includestays as is.Why "Clip"
Content-emitting composables are named with nouns, which rules out
Include.Patternis too generic: everything in this DSL is a pattern, and the name invitesPattern(Sequence { ... })misreadings. A clip is a prebuilt, self-contained unit placed on a timeline, which is exactly what this node does, and the word cannot be mistaken for something that wraps inline content.Semantics
The composition inside
Jindongis single-shot:compilePatterncomposes once and disposes the host (Jindong.kt:120-127), soComposeNodeupdate blocks never re-run after insertion.Cliptherefore follows the same idiom as every other node (value captured at compile time), and reactivity comes from threading the pattern through the trigger keys:HapticPatternis a data class, so the key comparison is structural.Acceptance criteria
apiDumpregenerated for both modules.Depends on #85 and #88.