From 04b68850d0494eeb2b1a894f50dc3abfe7b1364c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Forment?= Date: Thu, 5 Mar 2026 22:14:28 +0100 Subject: [PATCH] Wip --- .github/workflows/build-windows.yml | 25 +- .github/workflows/release.yml | 4 +- Cargo.toml | 2 +- build.rs | 17 +- crates/project/src/project.rs | 3 + demos/02.cagire | 8376 +-------------------------- docs/forth/prelude.md | 83 +- docs/getting-started/grid.md | 9 +- nsis/cagire.nsi | 98 + nsis/header.bmp | Bin 0 -> 25818 bytes nsis/sidebar.bmp | Bin 0 -> 154542 bytes scripts/build-all.sh | 19 +- src/app/dispatch.rs | 7 + src/app/scripting.rs | 93 +- src/app/undo.rs | 5 + src/commands.rs | 4 + src/input/main_page.rs | 3 +- src/input/modal.rs | 9 + src/input/mouse.rs | 5 + src/model/docs.rs | 2 +- src/model/palette.rs | 17 +- src/state/editor.rs | 1 + src/views/main_view.rs | 25 +- src/views/render.rs | 8 +- src/views/script_view.rs | 6 +- 25 files changed, 374 insertions(+), 8447 deletions(-) create mode 100644 nsis/cagire.nsi create mode 100644 nsis/header.bmp create mode 100644 nsis/sidebar.bmp diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index c14cd4b..adcd680 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -71,13 +71,24 @@ jobs: if: inputs.build-packages run: cargo xtask bundle cagire-plugins --release --target x86_64-pc-windows-msvc - - name: Install cargo-wix + - name: Install NSIS if: inputs.build-packages - run: cargo install cargo-wix + run: choco install nsis - - name: Build MSI installer + - name: Build NSIS installer if: inputs.build-packages - run: cargo wix --no-build --nocapture --package cagire -C -arch -C x64 + shell: pwsh + run: | + $version = (Select-String -Path Cargo.toml -Pattern '^version\s*=\s*"(.+)"' | Select-Object -First 1).Matches.Groups[1].Value + $root = (Get-Location).Path + $target = "x86_64-pc-windows-msvc" + & "C:\Program Files (x86)\NSIS\makensis.exe" ` + "-DVERSION=$version" ` + "-DCLI_EXE=$root\target\$target\release\cagire.exe" ` + "-DDESKTOP_EXE=$root\target\$target\release\cagire-desktop.exe" ` + "-DICON=$root\assets\Cagire.ico" ` + "-DOUTDIR=$root\target" ` + nsis/cagire.nsi - name: Upload CLI artifact if: inputs.build-packages @@ -93,12 +104,12 @@ jobs: name: cagire-windows-x86_64-desktop path: target/x86_64-pc-windows-msvc/release/cagire-desktop.exe - - name: Upload MSI artifact + - name: Upload installer artifact if: inputs.build-packages uses: actions/upload-artifact@v4 with: - name: cagire-windows-x86_64-msi - path: target/wix/*.msi + name: cagire-windows-x86_64-installer + path: target/cagire-*-setup.exe - name: Prepare plugin artifacts if: inputs.build-packages diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d9bbd9b..68ce2c2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -78,8 +78,8 @@ jobs: elif [[ "$name" == *-vst3 ]]; then base="${name%-vst3}" cd "$dir" && zip -r "../../release/${base}-vst3.zip" cagire-plugins.vst3 && cd ../.. - elif [[ "$name" == *-msi ]]; then - cp "$dir"/*.msi release/ + elif [[ "$name" == *-installer ]]; then + cp "$dir"/*-setup.exe release/ elif [[ "$name" == *-appimage ]]; then cp "$dir"/*.AppImage release/ elif [[ "$name" == *-desktop ]]; then diff --git a/Cargo.toml b/Cargo.toml index 67719ec..c629b68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,7 +86,7 @@ image = { version = "0.25", default-features = false, features = ["png"], option [target.'cfg(target_os = "linux")'.dependencies] cpal = { version = "0.17", optional = true, features = ["jack"] } -[target.'cfg(windows)'.build-dependencies] +[build-dependencies] winres = "0.1" [profile.release] diff --git a/build.rs b/build.rs index 631a969..72e0b5e 100644 --- a/build.rs +++ b/build.rs @@ -13,13 +13,22 @@ fn main() { println!("cargo:rustc-link-lib=oleaut32"); } - #[cfg(windows)] - { + if target_os == "windows" { + let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + let icon = format!("{manifest_dir}/assets/Cagire.ico"); + eprintln!("winres: manifest_dir = {manifest_dir}"); + eprintln!("winres: icon path = {icon}"); + eprintln!("winres: icon exists = {}", std::path::Path::new(&icon).exists()); + eprintln!("winres: OUT_DIR = {}", std::env::var("OUT_DIR").unwrap_or_default()); + eprintln!("winres: TARGET = {}", std::env::var("TARGET").unwrap_or_default()); let mut res = winres::WindowsResource::new(); - res.set_icon("assets/Cagire.ico") + res.set_icon(&icon) .set("ProductName", "Cagire") .set("FileDescription", "Forth-based music sequencer") .set("LegalCopyright", "Copyright (c) 2025 Raphaël Forment"); - res.compile().expect("Failed to compile Windows resources"); + if let Err(e) = res.compile() { + eprintln!("winres: compile error: {e:?}"); + panic!("Failed to compile Windows resources: {e}"); + } } } diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 1196756..dd84b98 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -543,6 +543,8 @@ pub struct Bank { pub patterns: Vec, #[serde(default)] pub name: Option, + #[serde(default)] + pub prelude: String, } impl Bank { @@ -560,6 +562,7 @@ impl Default for Bank { Self { patterns: (0..MAX_PATTERNS).map(|_| Pattern::default()).collect(), name: None, + prelude: String::new(), } } } diff --git a/demos/02.cagire b/demos/02.cagire index 4c88c11..dc27c5b 100644 --- a/demos/02.cagire +++ b/demos/02.cagire @@ -1,8375 +1 @@ -{ - "version": 1, - "banks": [ - { - "patterns": [ - { - "steps": [ - { - "i": 0, - "script": "0 8 12 rand ..\nc3 c4 g3 g2 4 pcycle key!\n0 1 2 choose 2\n6 12 rand pentatonic\n( inv ) rarely\n( inv ) sometimes arp note\ngrain sound 2 8 rand decay \n2 vib 0.125 2 / vibmod\n0.01 1.0 exprand pan\n2 release\n0.8 verb 1.0 verbdiff\n0.2 chorus\n1 morph\n0.0 1.0 rand \n0.0 1.0 rand timbre\n0.5 gain\n0.8 sustain\n2 8 rand release\n." - }, - { - "i": 4, - "script": "0 12 20 rand ..\nc3 c4 g3 g2 4 pcycle key!\n0 1 2 choose 2\n6 12 rand pentatonic\n( inv ) rarely\n( inv ) sometimes arp note\ngrain sound 2 8 rand decay \n2 vib 0.125 2 / vibmod\n0.01 1.0 exprand pan\n10 16 rand release\n0.8 verb 1.0 verbdiff\n0.2 chorus\n1 morph\n0.0 1.0 rand 0.0 1.0 rand timbre\n0.5 gain\n( . ) 2 every" - } - ], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - }, - { - "patterns": [ - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - }, - { - "steps": [], - "length": 16, - "speed": [ - 1, - 1 - ] - } - ], - "name": null - } - ], - "sample_paths": [], - "tempo": 120.0, - "playing_patterns": [ - [ - 0, - 0 - ] - ], - "prelude": ";; BIG VOICES" -} \ No newline at end of file +{"version":1,"banks":[],"tempo":120.0,"playing_patterns":[[0,0]],"prelude":""} diff --git a/docs/forth/prelude.md b/docs/forth/prelude.md index be03e6c..c27e4e2 100644 --- a/docs/forth/prelude.md +++ b/docs/forth/prelude.md @@ -1,18 +1,57 @@ -# The Prelude +# Preludes -You can define words in any step and they become available to all other steps. But as a project grows, definitions get scattered across steps and become hard to find and maintain. The **prelude** is a dedicated place for this. It is a project-wide Forth script that runs once before the first step plays. Definitions, variables, settings — everything in one place. Press `d` to open the prelude editor. Press `Esc` to save and close. Press `D` (Shift+d) to re-evaluate it without opening the editor. +Cagire has two levels of prelude: a **project prelude** shared by all banks, and **bank preludes** that travel with each bank. + +## Bank Prelude + +Each bank can carry its own prelude script. Press `p` to open the current bank's prelude editor. Press `Esc` to save, evaluate, and close. + +Bank preludes make banks self-contained. When you share a bank, its prelude travels with it — recipients get all the definitions they need without merging anything into their own project. + +```forth +: bass pulse sound 0.8 gain 400 lpf 1 lpd 8 lpe 0.6 width . ; +: pad sine sound 0.5 gain 2 spread 1.5 attack 0.4 verb . ; +``` + +Every step in that bank can now use `bass` and `pad`. Share the bank and the recipient gets these definitions automatically. + +## Project Prelude + +The project prelude is a global script shared across all banks. Press `P` (Shift+p) to open it. Use it for truly project-wide definitions, variables, and settings that every bank should see. + +```forth +c2 !root +0 !mode +42 seed +``` + +## Evaluation Order + +When preludes are evaluated (on playback start, project load, or pressing `d`): + +1. **Project prelude** runs first +2. **Bank 0 prelude** runs next (if non-empty) +3. **Bank 1 prelude**, then **Bank 2**, ... up to **Bank 31** + +Only non-empty bank preludes are evaluated. Last-evaluated wins for name collisions — a bank prelude can override a project-level definition. + +## Keybindings + +| Key | Action | +|-----|--------| +| `p` | Open current bank's prelude editor | +| `P` | Open project prelude editor | +| `d` | Re-evaluate all preludes (project + all banks) | ## Naming Your Sounds -The most common use of the prelude is to define words for your instruments. Without a prelude, every step that plays a bass has to spell out the full sound design or to create a new word before using it: +The most common use of a bank prelude is to define words for your instruments. Without a prelude, every step that plays a bass has to spell out the full sound design: ```forth -pulse sound 0.8 gain 400 lpf 1 lpd 8 lpe 0.6 width . +pulse sound c2 note 0.8 gain 400 lpf 1 lpd 8 lpe 0.6 width . ``` -Repeat this across eight steps without making a new word and you have eight copies of the same thing. Change the filter? Change it eight times. - -In the prelude, define it once: +In the bank prelude, define it once: ```forth : bass pulse sound 0.8 gain 400 lpf 1 lpd 8 lpe 0.6 width . ; @@ -20,22 +59,8 @@ In the prelude, define it once: Now every step just writes `c2 note bass`. Change the sound in one place, every step follows. -A step that used to read: - -```forth -pulse sound c2 note 0.8 gain 400 lpf 1 lpd 8 lpe 0.6 width . -``` - -Becomes: - -```forth -c2 note bass -``` - ## Building a Vocabulary -The prelude is where you build the vocabulary for your music. Not just instruments but any combination of code / words you want to reuse: - ```forth ;; instruments : bass pulse sound 0.8 gain 400 lpf 1 lpd 8 lpe 0.6 width . ; @@ -49,11 +74,11 @@ The prelude is where you build the vocabulary for your music. Not just instrumen : loud 0.9 gain ; ``` -By using the prelude and predefined words, steps become expressive and short. The prelude carries the design decisions; steps carry the composition. +Steps become expressive and short. The prelude carries the design decisions; steps carry the composition. ## Setting Initial State -The prelude also runs plain Forth, not just definitions. You can use it to set variables and seed the random generator: +The project prelude is the right place for global state: ```forth c2 !root @@ -61,18 +86,18 @@ c2 !root 42 seed ``` -Every step can then read `@root` and `@mode`. And `42 seed` makes randomness reproducible — same seed, same sequence every time you hit play. +Every step can then read `@root` and `@mode`. And `42 seed` makes randomness reproducible. -## When It Runs +## When Preludes Run -The prelude evaluates at three moments: +Preludes evaluate at three moments: 1. When you press **Space** to start playback 2. When you **load** a project -3. When you press **D** manually +3. When you press **d** manually -It runs once at these moments, not on every step. This makes it the right place for definitions and initial values. If you edit the prelude while playing, press `D` to push changes into the running session. New definitions take effect immediately; the next time a step runs, it sees the updated words. +They run once at these moments, not on every step. If you edit a prelude while playing, press `d` to push changes into the running session. ## What Not to Put Here -The prelude has no access to sequencer state. Words like `step`, `beat`, `iter`, and `phase` are meaningless here because no step is playing yet. Use the prelude for definitions and setup, not for logic that depends on timing. The prelude also should not emit sounds. It runs silently — any `.` calls here would fire before the sequencer clock is running and produce nothing useful. +Preludes have no access to sequencer state. Words like `step`, `beat`, `iter`, and `phase` are meaningless here because no step is playing yet. Use preludes for definitions and setup, not for logic that depends on timing. Preludes also should not emit sounds — any `.` calls here would fire before the sequencer clock is running. diff --git a/docs/getting-started/grid.md b/docs/getting-started/grid.md index 997322d..8e82517 100644 --- a/docs/getting-started/grid.md +++ b/docs/getting-started/grid.md @@ -32,12 +32,13 @@ To create mirrors: copy a step with `Ctrl+C`, then paste with `Ctrl+B` instead o - `Ctrl+D` — Duplicate selection - `Ctrl+H` — Harden mirrors (convert to independent copies) -## Prelude +## Preludes -The prelude is a Forth script that runs before every step, useful for defining shared variables and setup code. +Each bank has its own prelude — a Forth script for definitions and setup that travels with the bank when shared. There is also a project-wide prelude for global configuration. -- `p` — Open the prelude editor -- `d` — Evaluate the prelude +- `p` — Open current bank's prelude editor +- `P` — Open project prelude editor +- `d` — Evaluate all preludes (project + all banks) ## Pattern Controls diff --git a/nsis/cagire.nsi b/nsis/cagire.nsi new file mode 100644 index 0000000..65db774 --- /dev/null +++ b/nsis/cagire.nsi @@ -0,0 +1,98 @@ +; Cagire NSIS Installer Script +; Receives defines from command line: +; -DVERSION=x.y.z +; -DCLI_EXE=/path/to/cagire.exe +; -DDESKTOP_EXE=/path/to/cagire-desktop.exe +; -DICON=/path/to/Cagire.ico +; -DOUTDIR=/path/to/releases + +!include "MUI2.nsh" +!include "WordFunc.nsh" + +Name "Cagire ${VERSION}" +OutFile "${OUTDIR}\cagire-${VERSION}-windows-x86_64-setup.exe" +InstallDir "$PROGRAMFILES64\Cagire" +InstallDirRegKey HKLM "Software\Cagire" "InstallDir" +RequestExecutionLevel admin +Unicode True + +!define MUI_ICON "${ICON}" +!define MUI_UNICON "${ICON}" +!define MUI_ABORTWARNING + +!define MUI_HEADERIMAGE +!define MUI_HEADERIMAGE_BITMAP "header.bmp" +!define MUI_WELCOMEFINISHPAGE_BITMAP "sidebar.bmp" +!define MUI_UNWELCOMEFINISHPAGE_BITMAP "sidebar.bmp" + +!insertmacro MUI_PAGE_WELCOME +!insertmacro MUI_PAGE_COMPONENTS +!insertmacro MUI_PAGE_DIRECTORY +!insertmacro MUI_PAGE_INSTFILES +!insertmacro MUI_PAGE_FINISH + +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES + +!insertmacro MUI_LANGUAGE "English" + +Section "Cagire (required)" SecCore + SectionIn RO + SetOutPath "$INSTDIR" + File "/oname=cagire.exe" "${CLI_EXE}" + File "/oname=cagire-desktop.exe" "${DESKTOP_EXE}" + + WriteUninstaller "$INSTDIR\uninstall.exe" + WriteRegStr HKLM "Software\Cagire" "InstallDir" "$INSTDIR" + + ; Add/Remove Programs entry + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" "DisplayName" "Cagire" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" "DisplayVersion" "${VERSION}" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" "Publisher" "Raphael Forment" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" "UninstallString" '"$INSTDIR\uninstall.exe"' + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" "DisplayIcon" '"$INSTDIR\cagire-desktop.exe"' + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" "URLInfoAbout" "https://github.com/Bubobubobubobubo/cagire" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" "HelpLink" "https://cagire.raphaelforment.fr" + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" "NoModify" 1 + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" "NoRepair" 1 +SectionEnd + +Section "Add to PATH" SecPath + ReadRegStr $0 HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "Path" + StrCpy $0 "$0;$INSTDIR" + WriteRegExpandStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "Path" "$0" + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 +SectionEnd + +Section "Start Menu Shortcut" SecStartMenu + CreateDirectory "$SMPROGRAMS\Cagire" + CreateShortCut "$SMPROGRAMS\Cagire\Cagire.lnk" "$INSTDIR\cagire-desktop.exe" "" "$INSTDIR\cagire-desktop.exe" 0 + CreateShortCut "$SMPROGRAMS\Cagire\Uninstall.lnk" "$INSTDIR\uninstall.exe" +SectionEnd + +!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${SecCore} "Installs Cagire CLI and Desktop binaries." + !insertmacro MUI_DESCRIPTION_TEXT ${SecPath} "Add the install location to the PATH system environment variable." + !insertmacro MUI_DESCRIPTION_TEXT ${SecStartMenu} "Add a Cagire shortcut to the Start Menu." +!insertmacro MUI_FUNCTION_DESCRIPTION_END + +Section "Uninstall" + Delete "$INSTDIR\cagire.exe" + Delete "$INSTDIR\cagire-desktop.exe" + Delete "$INSTDIR\uninstall.exe" + RMDir "$INSTDIR" + + Delete "$SMPROGRAMS\Cagire\Cagire.lnk" + Delete "$SMPROGRAMS\Cagire\Uninstall.lnk" + RMDir "$SMPROGRAMS\Cagire" + + ; Remove from PATH + ReadRegStr $0 HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "Path" + ; Remove ";$INSTDIR" from the path string + ${WordReplace} $0 ";$INSTDIR" "" "+" $0 + WriteRegExpandStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "Path" "$0" + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" + DeleteRegKey HKLM "Software\Cagire" +SectionEnd diff --git a/nsis/header.bmp b/nsis/header.bmp new file mode 100644 index 0000000000000000000000000000000000000000..62985a8ab487a195815bb8ff00ba29e4fa65869c GIT binary patch literal 25818 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 literal 0 HcmV?d00001 diff --git a/nsis/sidebar.bmp b/nsis/sidebar.bmp new file mode 100644 index 0000000000000000000000000000000000000000..0e3b735877a41d8212340ed77f060dff525707a6 GIT binary patch literal 154542 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 t5Kssx1QY@a0fm4/dev/null; then - echo " Building MSI installer..." - cargo wix --no-build --nocapture --package cagire -C -arch -C x64 - cp target/wix/*.msi "$OUT/" 2>/dev/null && echo " MSI -> $OUT/" || true + # NSIS installer for Windows targets + if [[ "$os" == "windows" ]] && command -v makensis &>/dev/null; then + echo " Building NSIS installer..." + local version + version=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/') + local abs_root + abs_root=$(pwd) + makensis -DVERSION="$version" \ + -DCLI_EXE="$abs_root/$rd/cagire.exe" \ + -DDESKTOP_EXE="$abs_root/$rd/cagire-desktop.exe" \ + -DICON="$abs_root/assets/Cagire.ico" \ + -DOUTDIR="$abs_root/$OUT" \ + nsis/cagire.nsi + echo " Installer -> $OUT/cagire-${version}-windows-x86_64-setup.exe" fi # AppImage for Linux targets diff --git a/src/app/dispatch.rs b/src/app/dispatch.rs index ecc7f28..cc81fa1 100644 --- a/src/app/dispatch.rs +++ b/src/app/dispatch.rs @@ -469,6 +469,13 @@ impl App { AppCommand::SavePrelude => self.save_prelude(), AppCommand::EvaluatePrelude => self.evaluate_prelude(link), AppCommand::ClosePreludeEditor => self.close_prelude_editor(), + AppCommand::OpenBankPreludeEditor => self.open_bank_prelude_editor(), + AppCommand::SaveBankPrelude => self.save_bank_prelude(), + AppCommand::EvaluateBankPrelude => { + let bank = self.editor_ctx.bank; + self.evaluate_bank_prelude(bank, link); + } + AppCommand::CloseBankPreludeEditor => self.close_bank_prelude_editor(), // Periodic script AppCommand::OpenScriptModal(field) => self.open_script_modal(field), diff --git a/src/app/scripting.rs b/src/app/scripting.rs index f8f59d1..9652557 100644 --- a/src/app/scripting.rs +++ b/src/app/scripting.rs @@ -109,24 +109,101 @@ impl App { self.load_step_to_editor(); } - /// Evaluate the project prelude to seed variables and definitions. - pub fn evaluate_prelude(&mut self, link: &LinkState) { - let prelude = &self.project_state.project.prelude; + /// Switch the editor to the current bank's prelude script. + pub fn open_bank_prelude_editor(&mut self) { + let bank = self.editor_ctx.bank; + let prelude = &self.project_state.project.banks[bank].prelude; + let lines: Vec = if prelude.is_empty() { + vec![String::new()] + } else { + prelude.lines().map(String::from).collect() + }; + self.editor_ctx.editor.set_content(lines); + self.editor_ctx.editor.set_candidates(Arc::clone(&COMPLETION_CANDIDATES)); + self.editor_ctx + .editor + .set_completion_enabled(self.ui.show_completion); + let tree = SampleTree::from_paths(&self.audio.config.sample_paths); + self.editor_ctx.editor.set_sample_folders(tree.all_folder_names()); + self.editor_ctx.target = EditorTarget::BankPrelude; + self.ui.modal = Modal::Editor; + } + + pub fn save_bank_prelude(&mut self) { + let bank = self.editor_ctx.bank; + let text = self.editor_ctx.editor.content(); + self.project_state.project.banks[bank].prelude = text; + } + + pub fn close_bank_prelude_editor(&mut self) { + self.editor_ctx.target = EditorTarget::Step; + self.load_step_to_editor(); + } + + /// Evaluate a single bank's prelude. + pub fn evaluate_bank_prelude(&mut self, bank: usize, link: &LinkState) { + let prelude = &self.project_state.project.banks[bank].prelude; if prelude.trim().is_empty() { return; } let ctx = self.create_step_context(0, link); match self.script_engine.evaluate(prelude, &ctx) { - Ok(_) => { - self.ui.flash("Prelude evaluated", 150, FlashKind::Info); - } + Ok(_) => {} Err(e) => { - self.ui - .flash(&format!("Prelude error: {e}"), 300, FlashKind::Error); + let fallback = format!("Bank {}", bank + 1); + let bank_name = self.project_state.project.banks[bank] + .name + .as_deref() + .unwrap_or(&fallback); + self.ui.flash( + &format!("{bank_name} prelude error: {e}"), + 300, + FlashKind::Error, + ); } } } + /// Evaluate the project prelude and all bank preludes. + pub fn evaluate_prelude(&mut self, link: &LinkState) { + let project_prelude = &self.project_state.project.prelude; + if !project_prelude.trim().is_empty() { + let ctx = self.create_step_context(0, link); + match self.script_engine.evaluate(project_prelude, &ctx) { + Ok(_) => {} + Err(e) => { + self.ui + .flash(&format!("Project prelude error: {e}"), 300, FlashKind::Error); + return; + } + } + } + for bank_idx in 0..self.project_state.project.banks.len() { + let prelude = &self.project_state.project.banks[bank_idx].prelude; + if prelude.trim().is_empty() { + continue; + } + let ctx = self.create_step_context(0, link); + match self.script_engine.evaluate(prelude, &ctx) { + Ok(_) => {} + Err(e) => { + let bank_name = self.project_state.project.banks[bank_idx] + .name + .as_deref() + .map(String::from) + .unwrap_or_else(|| format!("Bank {}", bank_idx + 1)); + self.ui.flash( + &format!("{bank_name} prelude error: {e}"), + 300, + FlashKind::Error, + ); + return; + } + } + } + self.ui.flash("Preludes evaluated", 150, FlashKind::Info); + } + /// Evaluate a script and immediately send its audio commands. /// Returns collected `print` output, if any. pub fn execute_script_oneshot( diff --git a/src/app/undo.rs b/src/app/undo.rs index 9b5fa3a..9c1d1a8 100644 --- a/src/app/undo.rs +++ b/src/app/undo.rs @@ -42,6 +42,11 @@ impl App { let data = self.project_state.project.pattern_at(*bank, *pattern).clone(); Some(UndoScope::Pattern { bank: *bank, pattern: *pattern, data }) } + AppCommand::SaveBankPrelude => { + let bank = self.editor_ctx.bank; + let data = self.project_state.project.banks[bank].clone(); + Some(UndoScope::Bank { bank, data }) + } AppCommand::ResetBank { bank } | AppCommand::PasteBank { bank } | AppCommand::ImportBank { bank } => { diff --git a/src/commands.rs b/src/commands.rs index 37bcef3..e35fa92 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -301,6 +301,10 @@ pub enum AppCommand { SavePrelude, EvaluatePrelude, ClosePreludeEditor, + OpenBankPreludeEditor, + SaveBankPrelude, + EvaluateBankPrelude, + CloseBankPreludeEditor, // Onboarding DismissOnboarding, diff --git a/src/input/main_page.rs b/src/input/main_page.rs index c02089a..37f153e 100644 --- a/src/input/main_page.rs +++ b/src/input/main_page.rs @@ -82,7 +82,8 @@ pub(super) fn handle_main_page(ctx: &mut InputContext, key: KeyEvent, ctrl: bool KeyCode::Char(']') => ctx.dispatch(AppCommand::SpeedIncrease), KeyCode::Char('L') => ctx.dispatch(AppCommand::OpenPatternModal(PatternField::Length)), KeyCode::Char('S') => ctx.dispatch(AppCommand::OpenPatternModal(PatternField::Speed)), - KeyCode::Char('p') => ctx.dispatch(AppCommand::OpenPreludeEditor), + KeyCode::Char('p') => ctx.dispatch(AppCommand::OpenBankPreludeEditor), + KeyCode::Char('P') => ctx.dispatch(AppCommand::OpenPreludeEditor), KeyCode::Delete | KeyCode::Backspace => { let (bank, pattern) = (ctx.app.editor_ctx.bank, ctx.app.editor_ctx.pattern); if let Some(range) = ctx.app.editor_ctx.selection_range() { diff --git a/src/input/modal.rs b/src/input/modal.rs index 9454444..2ed41c7 100644 --- a/src/input/modal.rs +++ b/src/input/modal.rs @@ -351,6 +351,11 @@ pub(super) fn handle_modal_input(ctx: &mut InputContext, key: KeyEvent) -> Input ctx.dispatch(AppCommand::EvaluatePrelude); ctx.dispatch(AppCommand::ClosePreludeEditor); } + EditorTarget::BankPrelude => { + ctx.dispatch(AppCommand::SaveBankPrelude); + ctx.dispatch(AppCommand::EvaluateBankPrelude); + ctx.dispatch(AppCommand::CloseBankPreludeEditor); + } } ctx.dispatch(AppCommand::CloseModal); } @@ -364,6 +369,10 @@ pub(super) fn handle_modal_input(ctx: &mut InputContext, key: KeyEvent) -> Input ctx.dispatch(AppCommand::SavePrelude); ctx.dispatch(AppCommand::EvaluatePrelude); } + EditorTarget::BankPrelude => { + ctx.dispatch(AppCommand::SaveBankPrelude); + ctx.dispatch(AppCommand::EvaluateBankPrelude); + } }, KeyCode::Char('b') if ctrl => { editor.activate_sample_finder(); diff --git a/src/input/mouse.rs b/src/input/mouse.rs index b2e73a1..1e4965b 100644 --- a/src/input/mouse.rs +++ b/src/input/mouse.rs @@ -941,6 +941,11 @@ fn handle_modal_click(ctx: &mut InputContext, col: u16, row: u16, term: Rect) { ctx.dispatch(AppCommand::EvaluatePrelude); ctx.dispatch(AppCommand::ClosePreludeEditor); } + EditorTarget::BankPrelude => { + ctx.dispatch(AppCommand::SaveBankPrelude); + ctx.dispatch(AppCommand::EvaluateBankPrelude); + ctx.dispatch(AppCommand::CloseBankPreludeEditor); + } } ctx.dispatch(AppCommand::CloseModal); } diff --git a/src/model/docs.rs b/src/model/docs.rs index 8b671dd..89403ad 100644 --- a/src/model/docs.rs +++ b/src/model/docs.rs @@ -70,7 +70,7 @@ pub const DOCS: &[DocEntry] = &[ ), Topic("Brackets", include_str!("../../docs/forth/brackets.md")), Topic("Cycling", include_str!("../../docs/forth/cycling.md")), - Topic("The Prelude", include_str!("../../docs/forth/prelude.md")), + Topic("Preludes", include_str!("../../docs/forth/prelude.md")), Topic( "Cagire vs Classic", include_str!("../../docs/forth/oddities.md"), diff --git a/src/model/palette.rs b/src/model/palette.rs index 0d3e6b8..839c2bc 100644 --- a/src/model/palette.rs +++ b/src/model/palette.rs @@ -766,17 +766,26 @@ pub static COMMANDS: LazyLock> = LazyLock::new(|| { // === Prelude === CommandEntry { - name: "Edit Prelude", - description: "Open prelude editor", + name: "Edit Bank Prelude", + description: "Open current bank's prelude editor", category: "Prelude", keybinding: "p", pages: &[Main], normal_mode: false, + action: Some(PaletteAction::Resolve(|_| Some(AppCommand::OpenBankPreludeEditor))), + }, + CommandEntry { + name: "Edit Project Prelude", + description: "Open project-wide prelude editor", + category: "Prelude", + keybinding: "P", + pages: &[Main], + normal_mode: false, action: Some(PaletteAction::Resolve(|_| Some(AppCommand::OpenPreludeEditor))), }, CommandEntry { - name: "Evaluate Prelude", - description: "Re-evaluate prelude script", + name: "Evaluate All Preludes", + description: "Re-evaluate project and all bank preludes", category: "Prelude", keybinding: "d", pages: &[Main], diff --git a/src/state/editor.rs b/src/state/editor.rs index 4d27663..1e8844e 100644 --- a/src/state/editor.rs +++ b/src/state/editor.rs @@ -8,6 +8,7 @@ pub enum EditorTarget { #[default] Step, Prelude, + BankPrelude, } #[derive(Clone, Copy, PartialEq, Eq)] diff --git a/src/views/main_view.rs b/src/views/main_view.rs index 1bc14ef..a027c15 100644 --- a/src/views/main_view.rs +++ b/src/views/main_view.rs @@ -76,7 +76,11 @@ fn render_top_layout( } if has_preview { let user_words: HashSet = app.dict.lock().keys().cloned().collect(); - let has_prelude = !app.project_state.project.prelude.trim().is_empty(); + let has_prelude = !app.project_state.project.prelude.trim().is_empty() + || !app.project_state.project.banks[app.editor_ctx.bank] + .prelude + .trim() + .is_empty(); if has_prelude { let [script_area, prelude_area] = Layout::horizontal([Constraint::Fill(1), Constraint::Fill(1)]).areas(areas[idx]); @@ -195,7 +199,11 @@ fn render_viz_area( VizPanel::Lissajous => render_lissajous(frame, app, *panel_area), VizPanel::Preview => { let user_words = user_words_once.as_ref().expect("user_words initialized"); - let has_prelude = !app.project_state.project.prelude.trim().is_empty(); + let has_prelude = !app.project_state.project.prelude.trim().is_empty() + || !app.project_state.project.banks[app.editor_ctx.bank] + .prelude + .trim() + .is_empty(); if has_prelude { let [script_area, prelude_area] = if is_vertical_layout { Layout::vertical([Constraint::Fill(1), Constraint::Fill(1)]) @@ -655,11 +663,20 @@ pub(crate) fn render_prelude_preview( area: Rect, ) { let theme = theme::get(); - let prelude = &app.project_state.project.prelude; + let bank_prelude = &app.project_state.project.banks[app.editor_ctx.bank].prelude; + let (prelude, title) = if !bank_prelude.trim().is_empty() { + let bank_name = app.project_state.project.banks[app.editor_ctx.bank] + .name + .as_deref() + .unwrap_or("Bank"); + (bank_prelude.as_str(), format!(" {bank_name} Prelude ")) + } else { + (app.project_state.project.prelude.as_str(), " Prelude ".to_string()) + }; let block = Block::default() .borders(Borders::ALL) - .title(" Prelude ") + .title(title) .border_style(Style::new().fg(theme.ui.border)); let inner = block.inner(area); frame.render_widget(block, area); diff --git a/src/views/render.rs b/src/views/render.rs index 9924a66..46f4594 100644 --- a/src/views/render.rs +++ b/src/views/render.rs @@ -911,7 +911,13 @@ fn render_modal_editor( }; let title = match app.editor_ctx.target { - EditorTarget::Prelude => "Prelude".to_string(), + EditorTarget::Prelude => "Project Prelude".to_string(), + EditorTarget::BankPrelude => { + let bank = &app.project_state.project.banks[app.editor_ctx.bank]; + let fallback = format!("Bank {}", app.editor_ctx.bank + 1); + let bank_name = bank.name.as_deref().unwrap_or(&fallback); + format!("{bank_name} Prelude") + } EditorTarget::Step => { let step_num = app.editor_ctx.step + 1; let step = app.current_edit_pattern().step(app.editor_ctx.step); diff --git a/src/views/script_view.rs b/src/views/script_view.rs index 01813a7..8bc0169 100644 --- a/src/views/script_view.rs +++ b/src/views/script_view.rs @@ -114,7 +114,11 @@ fn render_sidebar(frame: &mut Frame, app: &App, area: Rect) { if app.audio.config.show_lissajous { constraints.push(Constraint::Fill(1)); } - let has_prelude = !app.project_state.project.prelude.trim().is_empty(); + let has_prelude = !app.project_state.project.prelude.trim().is_empty() + || !app.project_state.project.banks[app.editor_ctx.bank] + .prelude + .trim() + .is_empty(); if has_prelude { constraints.push(Constraint::Fill(1)); }