Per-layer modifier that adds noise to the sampled position and
rotation each frame. Pairs thematically with kaleido: both stack
on top of the keyframe sample, both per-layer, both deterministic
so editor and exported runtime render identically.
Math (src/lib/wiggle.ts):
- hash32 + layerSeeds(layerId): three uncorrelated 32-bit seeds per
layer, derived from the id so the same layer always wobbles the
same way.
- wiggleNoise(seed, t): sum-of-three-sines in [-1, 1]. Smooth (C∞),
cheap, no noise-lib dependency. Phase constants are irrational
ratios picked so the streams don't collapse into a low-period
pattern.
- applyWiggle(props, layer, time): adds amp * noise(seed, t*freq)
to x / y / rotation. Defaults: 8px position, 2° rotation, 2Hz.
Wire-in:
- src/lib/interpolate.ts sampleLayer: post-processes the keyframe
sample with applyWiggle. Every renderer goes through sampleLayer
(canvas2d, Konva, button-state, clip-internal), so the modifier
lights up everywhere from a single hook.
- src/lib/exportPlayer.ts engine: byte-for-byte JS mirror of
hash32 / layerSeeds / wiggleNoise / applyWiggle, plus the same
post-process branch in the engine's sample(). RUNTIME_VERSION
31 → 32.
Data + store:
- Layer.wiggle?: { amplitude?, rotation?, frequency? }. All sub-
fields optional with the documented defaults.
- store.setLayerWiggle(id, patch | null): patch object updates
individual fields with magnitude clamping (≥ 0); null deletes
the whole wiggle field.
UI (PropertiesPanel + i18n):
- New "Wiggle" section between Mask and Kaleidoscope. Toggle
(PhWaveSine icon) seeds the pleasant defaults; three RangeSliders
for position amplitude (0-64 px), rotation amplitude (0-45°),
and frequency (0-10 Hz). Hidden for button-asset layers
(consistent with Kaleido's hit-area constraint).
Tests (8 new under "wiggle — procedural shake modifier"):
- wiggleNoise determinism + [-1, 1] bounds across 4 seeds × ~100
time points.
- layerSeeds stability + the three seeds are pairwise distinct;
different ids yield different triples.
- applyWiggle on a layer without `wiggle` is a no-op (returns the
input reference unchanged).
- sampleLayer with wiggle: drift visible across a 1s window and
always within the configured amplitude bands.
- sampleLayer with wiggle is deterministic — same time, same drift.
- setLayerWiggle roundtrip + magnitude clamp + null-delete.
- PropertiesPanel Wiggle toggle writes the wiggle field with the
documented defaults.
- Exported runtime carries wiggleNoise / applyWiggle / wiggleSeeds
and bumps RUNTIME_VERSION to '32'.
Plan for the next two backlog items (motion-path overlay + canvas
eyedropper) is in claude.txt for later.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
30 lines
650 B
JSON
30 lines
650 B
JSON
{
|
|
"name": "ruwio",
|
|
"private": true,
|
|
"version": "1.2.10",
|
|
"type": "module",
|
|
"scripts": {
|
|
"dev": "vite",
|
|
"build": "vue-tsc --noEmit && vite build",
|
|
"preview": "vite preview",
|
|
"type-check": "vue-tsc --noEmit",
|
|
"pack": "bash scripts/pack.sh"
|
|
},
|
|
"dependencies": {
|
|
"@phosphor-icons/vue": "^2.2.1",
|
|
"gifenc": "^1.0.3",
|
|
"konva": "^9.3.16",
|
|
"pinia": "^2.2.6",
|
|
"upng-js": "^2.1.0",
|
|
"vue": "^3.5.13",
|
|
"vue-konva": "^3.1.2"
|
|
},
|
|
"devDependencies": {
|
|
"@types/node": "^22.10.2",
|
|
"@vitejs/plugin-vue": "^5.2.1",
|
|
"typescript": "^5.6.3",
|
|
"vite": "^6.0.3",
|
|
"vue-tsc": "^2.1.10"
|
|
}
|
|
}
|